Skip to main content
Every platform has its own knobs — Instagram’s REEL vs FEED, X’s replySettings, TikTok’s privacy and consent flags, YouTube’s madeForKids, LinkedIn’s PDF carousels. Postbreeze exposes these through a single field on each platform target:
platforms: [
  {
    accountId: "soc_…",
    platformOptions: {
      platform: "INSTAGRAM",
      kind: "REEL",
    },
  },
]
platformOptions is a discriminated union — the platform field picks which shape applies. Pass only the fields you want to override; everything else falls back to a sensible default.

Target-level fields (every platform)

These live next to platformOptions, not inside it. They apply to any platform that supports them.
FieldTypeDescription
accountIdstringRequired. The SocialAccount.id to publish to.
captionOverridestring (≤10,000)Per-platform caption that overrides the post-level content. Useful when one platform needs a different tone, length, or set of hashtags.
firstCommentstring (≤2,000)Auto-posts as the first reply once the main post is live. Supported on Instagram, Facebook, X, YouTube, TikTok, LinkedIn, Threads. Ignored on platforms that don’t have a comments surface.
platformOptionsobjectPlatform-specific options (this page). Discriminated by platform.
mediaIdsstring[]Overrides the post-level media for this target only. Use when one platform needs a different crop or asset.
{
  "accountId": "soc_…",
  "captionOverride": "Different caption for X — shorter, punchier.",
  "firstComment": "Drop a 🔥 if you want the deep-dive thread.",
  "platformOptions": { "platform": "X", "replySettings": "following" }
}
The full Zod schema lives in packages/shared/src/index.ts. This page is the human-readable copy.

Instagram

FieldTypeDescription
platform"INSTAGRAM"Discriminator. Required.
kind"FEED" | "REEL"Which Instagram surface to publish to. Defaults to "FEED".
{
  "platform": "INSTAGRAM",
  "kind": "REEL"
}
Constraints
  • 📐 Feed posts require aspect ratio between 4:5 (0.8) and 1.91:1.
  • 📱 Reels must be a single 9:16 video, 3–90 seconds.
  • 🎠 Feed carousels support up to 10 media items.
  • 🚫 Stories are not supported in v1 — they’re rejected at validation.
  • 🚫 Mixing image + video in one Feed post is rejected by the API.
  • 💬 firstComment is supported on Feed posts and Reels (not stories — and stories don’t ship in v1 anyway).

Facebook

FieldTypeDescription
platform"FACEBOOK_PAGE"Discriminator. Required.
kind"FEED" | "PHOTO" | "PHOTO_CAROUSEL" | "VIDEO" | "REEL"Publishing surface. Defaults to "FEED". With media attached, FEED is auto-normalized to PHOTO or PHOTO_CAROUSEL.
linkstring (URL)Optional outbound link. With kind: "FEED", Facebook auto-generates the link preview card from the URL’s Open Graph tags.
reelTitlestring (≤2,200)Optional Reel title prepended to the description on publish.
{
  "platform": "FACEBOOK_PAGE",
  "kind": "REEL",
  "reelTitle": "Behind the launch"
}
Constraints
  • 🚫 Cannot mix videos and images in the same post.
  • ✅ Up to 10 images for Feed photo carousels.
  • 🎬 Reels must be 9:16, between 3 and 90 seconds.
  • 📊 Reels are capped at 30 publishes per Page per 24h by Meta.
  • 🔗 Use link (with kind: "FEED") for OG-card link previews.
  • 💬 firstComment is supported on every surface except Reels.

X (Twitter)

FieldTypeDescription
platform"X"Discriminator. Required.
replySettings"everyone" | "following" | "mentionedUsers"Who can reply. Defaults to "everyone". Enforced server-side by X.
threadPartsstring[] (each ≤4,000, up to 25 items)Tail of a thread. When non-empty, each entry posts as a separate tweet threaded under the first. content is the FIRST tweet in the thread.
replyToIdstringOptional tweet ID — turns this post into a reply to an existing tweet.
{
  "platform": "X",
  "replySettings": "following",
  "threadParts": [
    "Here's the second tweet in the thread.",
    "And the third — wrapping up with the link → https://example.com"
  ]
}
Constraints
  • 🖼️ Up to 4 images or 1 video per tweet — never a mix.
  • 🧵 threadParts adds up to 25 tweets after the root. Each entry inherits no media; only the root tweet carries the post’s mediaItems.
  • 💬 firstComment is published as a reply to the root tweet, not the last thread part.
  • 🌍 Tweet text is always globally visible — X doesn’t expose geo-restriction on text.

LinkedIn (Personal)

FieldTypeDescription
platform"LINKEDIN_PERSON"Discriminator. Required.
visibility"PUBLIC" | "CONNECTIONS"Who can see the post. Defaults to "PUBLIC".
postAsPdfCarouselbooleanComposite the attached images into a single PDF and post as a “document”. LinkedIn renders it as a swipeable carousel under the post.
pdfCarouselTitlestring (≤100)Title shown above the PDF carousel. Required when postAsPdfCarousel is true.
{
  "platform": "LINKEDIN_PERSON",
  "visibility": "PUBLIC",
  "postAsPdfCarousel": true,
  "pdfCarouselTitle": "Q2 launch retro"
}
Constraints
  • 🖼️ Up to 20 images per post.
  • 🚫 Multi-video posts are not supported.
  • 📄 Single PDF document posts supported — upload the PDF and attach with type: "document". See Media uploads → LinkedIn PDFs.
  • 🔗 Link previews are auto-generated when no media is attached.

LinkedIn (Company)

Same shape as LinkedIn Personal, with the discriminator platform: "LINKEDIN_COMPANY". Use for organization pages the connected user administers.
FieldTypeDescription
platform"LINKEDIN_COMPANY"Discriminator. Required.
visibility"PUBLIC" | "CONNECTIONS"Kept for shape parity — company actors always post publicly, no matter what’s passed.
postAsPdfCarouselbooleanSee LinkedIn Personal above.
pdfCarouselTitlestring (≤100)Title shown above the PDF carousel.
{
  "platform": "LINKEDIN_COMPANY",
  "postAsPdfCarousel": true,
  "pdfCarouselTitle": "Quarterly numbers"
}
Constraints
  • 🏢 One SocialAccount per administered organization. Use the per-org accountId to fan out to multiple pages.
  • 📊 Org-page analytics require LinkedIn Marketing Developer Platform approval — until that lands, the analytics surface shows an “approval pending” banner. Posting still works.

TikTok (Personal)

Required by TikTok. privacy has no default — you must pass one of the four values below. Branded-content (brandContentToggle: true) is only allowed with privacy: "PUBLIC_TO_EVERYONE".
FieldTypeDescription
platform"TIKTOK_PERSONAL"Discriminator. Required.
privacy"PUBLIC_TO_EVERYONE" | "MUTUAL_FOLLOW_FRIENDS" | "FOLLOWER_OF_CREATOR" | "SELF_ONLY"Required. TikTok’s Content Sharing Guidelines forbid a default here — the creator must pick a value their creator_info API confirmed is allowed for their account.
allowCommentsbooleanWhether viewers can comment. Defaults to false.
allowDuetbooleanWhether viewers can duet. Defaults to false.
allowStitchbooleanWhether viewers can stitch. Defaults to false.
autoAddMusicbooleanLet TikTok auto-add a recommended music track. Defaults to false. Photo posts only.
brandOrganicToggleboolean”Your Brand” disclosure — content promotes the creator’s own brand. Defaults to false. Surfaced to TikTok as brand_organic_toggle.
brandContentToggleboolean”Branded Content” disclosure — paid partnership / third-party brand. Defaults to false. Surfaced to TikTok as brand_content_toggle.
photoTitlestring (≤90 UTF-16 runes)Photo posts only — TikTok exposes a short metadata title separate from the caption. Ignored for video posts.
{
  "platform": "TIKTOK_PERSONAL",
  "privacy": "PUBLIC_TO_EVERYONE",
  "allowComments": true,
  "allowDuet": false,
  "allowStitch": false,
  "brandContentToggle": true
}
Constraints
  • 🎬 Videos publish via PULL_FROM_URL; the host of the media URL must be on TikTok’s verified-domain list (your R2 public bucket).
  • 📸 Photo carousels support up to 35 images.
  • 📝 Video captions: up to 2,200 characters. Photo titles capped at 90 characters — use content for longer descriptions.
  • 🔒 While the app is in TikTok Sandbox, privacy is forced to "SELF_ONLY" regardless of what you pass — that’s a TikTok constraint until App Review lands.
  • 🤝 Branded content cannot be SELF_ONLY, MUTUAL_FOLLOW_FRIENDS, or FOLLOWER_OF_CREATOR. Validation rejects the combination pre-flight.

TikTok (Business)

Same shape as TikTok Personal, with the discriminator platform: "TIKTOK_BUSINESS". Use for accounts authenticated through TikTok for Business.
{
  "platform": "TIKTOK_BUSINESS",
  "privacy": "PUBLIC_TO_EVERYONE",
  "allowComments": true,
  "brandContentToggle": false
}
The reserved TIKTOK_BUSINESS slot exists for accounts that grant the Business OAuth flow; the publish shape and validation rules are identical to Personal.

YouTube

FieldTypeDescription
platform"YOUTUBE"Discriminator. Required.
visibility"PUBLIC" | "UNLISTED" | "PRIVATE"Defaults to "PUBLIC".
madeForKidsbooleanCOPPA flag — required by YouTube on every upload. Videos marked made-for-kids have restricted features (no comments, no notifications, limited ad targeting). Defaults to false.
youtubeTitlestring (≤100)Optional title that overrides the first line of content. YouTube splits title from description; this field carries the override.
{
  "platform": "YOUTUBE",
  "visibility": "UNLISTED",
  "madeForKids": false,
  "youtubeTitle": "Launch day — full walkthrough"
}
Constraints
  • 🎬 YouTube targets accept a single video, no images.
  • ⏱️ Videos ≤ 3 minutes in 9:16 are automatically published as YouTube Shorts; longer videos publish as regular videos. Postbreeze doesn’t override this — it’s YouTube’s classification.
  • 🖼️ Custom thumbnails work for regular videos only (not Shorts).
  • 💬 firstComment is supported and posted as a top-level comment after upload completes.
  • 🚫 Tags, category overrides, AI-disclosure flag (containsSyntheticMedia) are not exposed in v1 — defaults are applied server-side (categoryId: "22" “People & Blogs”).

Pinterest

FieldTypeDescription
platform"PINTEREST"Discriminator. Required.
boardstringPinterest board ID. Required by the API for any pin.
titlestring (≤100)Optional pin title — distinct from the post content, which becomes the pin description.
linkstring (URL)Optional outbound link the pin opens when clicked.
{
  "platform": "PINTEREST",
  "board": "1234567890123456789",
  "title": "Spring lookbook",
  "link": "https://example.com/spring"
}
Constraints
  • 📌 Every pin requires a board. There is no default board fallback in v1.
  • 🖼️ Pinterest carousels accept up to 5 images.
  • 🚫 Video pins are not supported in v1.
  • 🔗 link becomes the pin’s destination — leave it unset for image-only inspiration pins.

Threads

FieldTypeDescription
platform"THREADS"Discriminator. Required.
kind"TEXT" | "IMAGE" | "VIDEO" | "CAROUSEL"Publishing surface. Defaults to "TEXT". The compose flow normally auto-derives it from the attached media (no media → TEXT, single image → IMAGE, etc.); set it explicitly if you want to force a surface.
threadPartsstring[] (each ≤500, up to 25 items)Optional thread tail. When non-empty, each entry posts as a separate Threads post chained via reply_to_id under the previous one. content is the FIRST post in the thread.
{
  "platform": "THREADS",
  "kind": "TEXT",
  "threadParts": [
    "Second post in the thread — explaining the why.",
    "Third post — the punchline."
  ]
}
Constraints
  • 📝 Each post (root + every follow-up) is capped at 500 characters — Threads has no “See more” fold. The publisher rejects pre-flight if any part is over.
  • 🧵 threadParts adds up to 25 follow-ups after the root. Each follow-up is text-only; only the root post carries the attached mediaItems.
  • 🎠 Carousels accept 2–20 mixed items (images and videos) on the root post.
  • 🎬 Videos up to 5 minutes / 1 GB.
  • 📊 Posting limits: 250 published posts / 24h, 1,000 replies / 24h. Each follow-up counts toward the reply quota.
  • 💬 firstComment is posted as a reply to the root post, not the last thread part.

Cross-platform example

One post fanned out to four platforms, each with its own platformOptions, per-target caption override, and first-comment:
await postbreeze.posts.create({
  content: "We just launched 🚀",
  mediaItems: [{ url: heroUrl, type: "image" }],
  platforms: [
    {
      accountId: "soc_ig_…",
      firstComment: "Link in bio! 🔗",
      platformOptions: { platform: "INSTAGRAM", kind: "FEED" },
    },
    {
      accountId: "soc_x_…",
      captionOverride: "We just launched 🚀 → https://example.com",
      platformOptions: {
        platform: "X",
        replySettings: "everyone",
        threadParts: [
          "Here's what's new — a thread 🧵",
          "Schedule once, publish everywhere. No spreadsheet required.",
        ],
      },
    },
    {
      accountId: "soc_li_…",
      firstComment: "What do you think? Drop a comment below 👇",
      platformOptions: {
        platform: "LINKEDIN_PERSON",
        visibility: "PUBLIC",
      },
    },
    {
      accountId: "soc_tt_…",
      platformOptions: {
        platform: "TIKTOK_PERSONAL",
        privacy: "PUBLIC_TO_EVERYONE",
        allowComments: true,
        allowDuet: false,
        allowStitch: false,
      },
    },
  ],
});
Defaults that kick in if you omit platformOptions
  • Instagram → kind: "FEED"
  • Facebook → kind: "FEED"
  • X → replySettings: "everyone"
  • LinkedIn (Personal/Company) → visibility: "PUBLIC"
  • YouTube → visibility: "PUBLIC", madeForKids: false
  • Threads → kind derived from media
The exceptions are TikTok (privacy has no default) and Pinterest (board has no default) — those two targets require platformOptions with at least the required field, or the post is rejected at validation.