Postato Docs
MCP ToolsTools

Publish Post

Creates and queues a post for delivery to a social platform. Returns immediately with status "pending" — delivery is asynchronous. Use get_post_status to poll f

publish_post

Creates and queues a post for delivery to a social platform. Returns immediately with status "pending" — delivery is asynchronous. Use get_post_status to poll for the final delivery outcome. One post = one platform. For multiple platforms, call publish_post multiple times. Supply Idempotency-Key via the idempotencyKey parameter to safely retry.

Parameters

ParameterTypeRequiredDescription
platforminstagram | twitter | x | linkedin | tiktok | youtubeyesTarget social platform.
accountIdstringyesConnected social account ID for this platform.
statuspublish | scheduled | draftyespublish = immediate, scheduled = requires scheduledAt, draft = save without publishing.
postTypestringyesType of post. Instagram: feed, reel, story, carousel. Twitter: tweet, thread. LinkedIn: post, document. TikTok: video, photo. YouTube: video, short. Pinterest: pin.
contentstring | array<object>yesPost content. String for simple posts, array for threads. String is normalized to [{text, media}] internally.
mediaarray<object>noTop-level media items. Only valid when content is a string. For threads (content is array), put media inside each content item.
optionsobjectnoPlatform-specific options. Instagram: collaborators, coverUrl, shareToFeed, thumbOffset. YouTube: title, privacy, categoryId, madeForKids, tags. Pinterest: boardId, destinationLink, title. TikTok: disableComments, disableDuet, disableStitch.
scheduledAtstringnoISO-8601 future timestamp. Required when status is "scheduled".
idempotencyKeystringnoUnique key to deduplicate retries. Same key always returns the same post.
workspaceIdstringnoWorkspace ID. Required if your API key accesses multiple workspaces.

When to use

Call publish_post whenever you want to create and deliver a post to a single social network. One tool invocation = one platform. For cross-posting, issue multiple calls in parallel — each gets its own postId and retries independently.

Typical flow

  1. Resolve the accountId via list_accounts (or from the user's last-known selection).
  2. Build the content — string for simple posts, array for threads.
  3. Attach any media by id (from upload_media or create_upload_url) or url (public URL, fetched async).
  4. Generate an idempotencyKey (UUID per logical post).
  5. Call publish_post and record the returned postId.
  6. Optionally poll get_post_status or wait for the post.published webhook.

Example

{
  "workspaceId": "wks_01H...",
  "platform": "twitter",
  "accountId": "acc_01H...",
  "status": "publish",
  "postType": "tweet",
  "content": "Shipping our new API-first publishing platform today.",
  "idempotencyKey": "8f2a4b1c-7d9e-4c3b-9a1f-5e6d8c7b4a3f"
}

Thread example:

{
  "workspaceId": "wks_01H...",
  "platform": "twitter",
  "accountId": "acc_01H...",
  "status": "publish",
  "postType": "thread",
  "content": [
    { "text": "Part 1 of the thread." },
    { "text": "Part 2, continuing the idea." },
    { "text": "Part 3, wrap-up." }
  ],
  "idempotencyKey": "c4e1d2b3-a4f5-6b78-9c0d-1e2f3a4b5c6d"
}

Gotchas

  • status: "scheduled" requires a scheduledAt ISO 8601 timestamp in the future.
  • status: "draft" requires the posts.create_draft permission; publish and scheduled require posts.publish.
  • Mixing array content with a top-level media field is a validation error. Attach media to individual content items instead.
  • On Instagram, a single content item with 2+ media is auto-promoted to postType: "carousel". You don't need to pre-classify.
  • The response returns in milliseconds with status: "queued". Actual delivery to the network happens asynchronously — do not assume the post is live without polling or webhooks.

On this page