Skip to main content
Glama

Publish a post now

post_to_social
Destructive

Publish a post immediately and publicly to multiple social platforms at once with platform-specific text and media via PostWire.

Instructions

Publishes a post immediately and publicly to the listed platforms through the social accounts connected to the user's PostWire account. A published post cannot be withdrawn from PostWire. Accepts one text for all platforms or a separate per_platform draft for each. YouTube requires video_url; TikTok requires video_url or photos (photo_url or media); Instagram requires a photo or video, and two or more media items make a carousel. Every platform must already be connected; otherwise nothing is published and the error names the missing ones. The same payload sent twice within 2 minutes is refused as a duplicate unless idempotency_key differs. When a platform is connected in more than one brand and brand_id is omitted, nothing is published and the error lists the brands. Returns { posted, published_to, results: [{ platform, ok, id?, url?, account?, error? }] }, where account and published_to name the handle and brand each post went to. After the account's first post through this connection, next_step proposes a week of posts on the same topic for the text networks it went to (its topic and platforms); nothing is queued until the person asks for it. The plan sets how many networks one post goes out to (Free: 2): only the first platforms in the list are published and each of the others comes back with ok: false, held: true and code networks_per_post (its version was written and not sent), listed in held_networks with a one-sentence held_message, and message_for_user says it in plain words for the person; every network can still be connected and written for. TikTok and Instagram videos may still be processing when this returns (status processing, no url yet). When the networks-per-post or the monthly post limit stops a platform, the result also names the plan that lifts it, its price and a checkout link, and, for a free account that has not had one, a link to Pro with the first month 50% off (trial_offer: paid today, then the regular monthly price, cancel anytime). Such an account also gets the trial link once after its first post from an assistant, with a one-sentence trial_message. X (Twitter) is a pay-per-use add-on on paid plans: each X post uses X credits (1 for a plain post, 10 for a post with a link, +1 per image or video) from the plan's monthly X credits, then from top-up credits; a post without enough credits is not sent to X and its result says how to get more. An X thread: per_platform.x.thread is the list of posts after per_platform.x.text (up to 25, each at most 280 characters as X counts them, a link counts 23); per_platform.x.reply is one more post under the last one, the usual place for a link. Each post of a thread or reply is an X post: it uses credits by the same rule and counts toward the daily X limit, and the whole chain is reserved before anything is sent. Write a thread only when the user asks for one. The X result then has thread.tweets (every post's id), thread_url, and thread.status: complete, or pending when X refused a later post (the first post stays published and PostWire retries the rest on its own). If the brand's approval rules or a limit on this API key or connected app hold the post, nothing is published: the result has status "pending_approval", the post's id and approval_id, who was notified and a review link, and the post goes out once a person approves it from the emailed link or the PostWire dashboard — an AI assistant or an API key cannot approve it. A limit on this key or app can also refuse a post with code key_network_not_allowed, key_brand_not_allowed or key_monthly_cap_reached.

Input Schema

NameRequiredDescriptionDefault
textNoPost text used for every platform that has no per_platform draft.
mediaNoSeveral images (or images and videos) in one post, in order: an Instagram carousel (up to 10), TikTok photo post (up to 35 images; PNG is converted to JPEG automatically for Instagram and TikTok), Bluesky (up to 4 images), Mastodon (up to 4), LinkedIn (up to 20 images, or one PDF document). Networks that take one item get the first. Each item: { url, type: image|video|document, alt? }.
titleNoTitle, used by YouTube.
privacyNoWho can see the TikTok and YouTube posts: public (everyone), unlisted (YouTube), friends (TikTok mutual followers) or private (only the account owner). TikTok asks that the account owner choose this for each TikTok post. Without it a TikTok post goes out private and YouTube uses the channel default.
brand_idNoWhich brand's accounts to use. Omit to use the default brand.
photo_urlNoPublic https URL of an image.
platformsYesPlatforms to publish to, all in one call, e.g. ["linkedin","bluesky"].
video_urlNoPublic https URL of a video. Required for YouTube; TikTok takes a video or photos.
per_platformNoPer-platform drafts: { "<platform>": { "text": "…", "title": "…", "tags": ["…"] } }. X, Bluesky and Mastodon also take "thread" (the posts after text, in order, each a reply to the one before; media stays on the first post). LinkedIn, X, Bluesky and Mastodon take "first_comment" (posted by the author right under the post, or under the last post of a thread: the place for the link). X also calls it "reply". Pass the thread and first_comment that generate_posts returned as they are.
upload_methodNoTikTok only, videos only: the "upload method" editors use so TikTok leaves the file as exported. PostWire rewrites the MP4 header on the way to TikTok (nothing is re-encoded, no size limit beyond the usual 1 GB). max is the usual choice; safe changes the header only. Off unless given.
idempotency_keyNoOptional unique key; a repeat with the same key within 24 h is refused instead of posted twice.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed18 schema fields changedv0.4.0
    • addedInput schema / additionalProperties
      Added value: +false
    • addedInput schema / properties / brand_id
      Added value: +{
      +  "description": "Which brand's accounts to use. Omit to use the default brand.",
      +  "type": "string"
      +}
    • addedInput schema / properties / idempotency_key
      Added value: +{
      +  "description": "Optional unique key; a repeat with the same key within 24 h is refused instead of posted twice.",
      +  "maxLength": 200,
      +  "type": "string"
      +}
    • addedInput schema / properties / media
      Added value: +{
      +  "description": "Several images (or images and videos) in one post, in order: an Instagram carousel (up to 10), TikTok photo post (up to 35 images; PNG is converted to JPEG automatically for Instagram and TikTok), Bluesky (up to 4 images), Mastodon (up to 4), LinkedIn (up to 20 images, or one PDF document). Networks that take one item get the first. Each item: { url, type: image|video|document, alt? }.",
      +  "items": {
      +    "additionalProperties": false,
      +    "properties": {
      +      "alt": {
      +        "description": "Alt text (used by Bluesky, Mastodon and LinkedIn).",
      +        "maxLength": 1500,
      +        "type": "string"
      +      },
      +      "title": {
      +        "description": "Document title, used by LinkedIn.",
      +        "maxLength": 200,
      +        "type": "string"
      +      },
      +      "type": {
      +        "description": "Default image.",
      +        "enum": [
      +          "image",
      +          "video",
      +          "document"
      +        ],
      +        "type": "string"
      +      },
      +      "url": {
      +        "description": "Public https URL of the file.",
      +        "format": "uri",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "url"
      +    ],
      +    "type": "object"
      +  },
      +  "maxItems": 35,
      +  "minItems": 1,
      +  "type": "array"
      +}
    • addedInput schema / properties / per_platform / additionalProperties
      Added value: +{
      +  "properties": {
      +    "canonical_url": {
      +      "description": "Dev.to and Hashnode: where the article was first published.",
      +      "format": "uri",
      +      "type": "string"
      +    },
      +    "first_comment": {
      +      "description": "LinkedIn, X, Bluesky, Mastodon: the author's first comment, posted right after the post (under the last post of a thread) — where the link goes. Bluesky <= 300 characters, Mastodon <= 500, X <= 280 (an X post: it uses X credits), LinkedIn <= 1250. Other networks report it as not posted.",
      +      "maxLength": 1500,
      +      "type": "string"
      +    },
      +    "reply": {
      +      "description": "X only: the same as first_comment — one post under the last post of the chain, e.g. the link.",
      +      "maxLength": 1000,
      +      "type": "string"
      +    },
      +    "status": {
      +      "description": "Blogs: publish now, or save a draft on the blog.",
      +      "enum": [
      +        "publish",
      +        "draft"
      +      ],
      +      "type": "string"
      +    },
      +    "summary": {
      +      "description": "Blogs: the article's excerpt / meta description.",
      +      "maxLength": 400,
      +      "type": "string"
      +    },
      +    "tags": {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "text": {
      +      "type": "string"
      +    },
      +    "thread": {
      +      "description": "X, Bluesky, Mastodon: the posts of a thread after text, each a reply to the one before. X: max 25, each <= 280 as X counts. Bluesky: max 9 (10 posts in all), each <= 300 characters. Mastodon: max 9, each <= 500 characters or the server's own limit. Each result lists every post's URL (thread.posts); if a later post is refused, the earlier ones stay published and thread.not_posted lists the rest.",
      +      "items": {
      +        "maxLength": 1000,
      +        "type": "string"
      +      },
      +      "maxItems": 25,
      +      "type": "array"
      +    },
      +    "title": {
      +      "type": "string"
      +    }
      +  },
      +  "type": "object"
      +}
    • changedInput schema / properties / per_platform / description
      Previous value: -"native drafts from generate_posts, e.g. { youtube:{text,title,tags}, x:{text} }"New value: +"Per-platform drafts: { \"<platform>\": { \"text\": \"…\", \"title\": \"…\", \"tags\": [\"…\"] } }. X, Bluesky and Mastodon also take \"thread\" (the posts after text, in order, each a reply to the one before; media stays on the first post). LinkedIn, X, Bluesky and Mastodon take \"first_comment\" (posted by the author right under the post, or under the last post of a thread: the place for the link). X also calls it \"reply\". Pass the thread and first_comment that generate_posts returned as they are."
    • changedInput schema / properties / photo_url / description
      Previous value: -"optional public URL of a photo"New value: +"Public https URL of an image."
    • addedInput schema / properties / photo_url / format
      Added value: +"uri"
    • changedInput schema / properties / platforms / description
      Previous value: -"e.g. ['tiktok','youtube','bluesky'] — posts to all in one call"New value: +"Platforms to publish to, all in one call, e.g. [\"linkedin\",\"bluesky\"]."
    • addedInput schema / properties / platforms / items / enum
      Added value: +[
      +  "telegram",
      +  "bluesky",
      +  "mastodon",
      +  "discord",
      +  "wordpress",
      +  "devto",
      +  "hashnode",
      +  "slack",
      +  "nostr",
      +  "tiktok",
      +  "youtube",
      +  "reddit",
      +  "linkedin",
      +  "facebook",
      +  "instagram",
      +  "x"
      +]
    • addedInput schema / properties / platforms / minItems
      Added value: +1
    • changedInput schema / properties / privacy / description
      Previous value: -"optional: private | public | unlisted (YouTube)"New value: +"Who can see the TikTok and YouTube posts: public (everyone), unlisted (YouTube), friends (TikTok mutual followers) or private (only the account owner). TikTok asks that the account owner choose this for each TikTok post. Without it a TikTok post goes out private and YouTube uses the channel default."
    • addedInput schema / properties / privacy / enum
      Added value: +[
      +  "public",
      +  "unlisted",
      +  "friends",
      +  "private"
      +]
    • changedInput schema / properties / text / description
      Previous value: -"post text / caption (shared fallback if a platform has no per_platform draft)"New value: +"Post text used for every platform that has no per_platform draft."
    • changedInput schema / properties / title / description
      Previous value: -"optional title (used by YouTube)"New value: +"Title, used by YouTube."
    • addedInput schema / properties / upload_method
      Added value: +{
      +  "description": "TikTok only, videos only: the \"upload method\" editors use so TikTok leaves the file as exported. PostWire rewrites the MP4 header on the way to TikTok (nothing is re-encoded, no size limit beyond the usual 1 GB). max is the usual choice; safe changes the header only. Off unless given.",
      +  "enum": [
      +    "max",
      +    "safe"
      +  ],
      +  "type": "string"
      +}
    • changedInput schema / properties / video_url / description
      Previous value: -"optional public URL of a video (required for TikTok/YouTube)"New value: +"Public https URL of a video. Required for YouTube; TikTok takes a video or photos."
    • addedInput schema / properties / video_url / format
      Added value: +"uri"
  2. Changed7 schema fields changedv0.1.1
    • addedInput schema / properties / per_platform
      Added value: +{
      +  "description": "native drafts from generate_posts, e.g. { youtube:{text,title,tags}, x:{text} }",
      +  "type": "object"
      +}
    • changedInput schema / properties / platforms / description
      Previous value: -"e.g. ['x','tiktok','bluesky']"New value: +"e.g. ['tiktok','youtube','bluesky'] — posts to all in one call"
    • addedInput schema / properties / privacy
      Added value: +{
      +  "description": "optional: private | public | unlisted (YouTube)",
      +  "type": "string"
      +}
    • changedInput schema / properties / text / description
      Previous value: -"post text / caption"New value: +"post text / caption (shared fallback if a platform has no per_platform draft)"
    • addedInput schema / properties / title
      Added value: +{
      +  "description": "optional title (used by YouTube)",
      +  "type": "string"
      +}
    • changedInput schema / properties / video_url / description
      Previous value: -"optional public URL of a video"New value: +"optional public URL of a video (required for TikTok/YouTube)"
    • changedInput schema / required
      Previous value: -[
      -  "platforms",
      -  "text"
      -]New value: +[
      +  "platforms"
      +]
  3. First observedv0.1.0

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructive=true and idempotent=false, but the description adds extensive behavioral detail beyond them: posts cannot be withdrawn, duplicates within 2 minutes are refused, brand ambiguity blocks publishing, approvals must be manual, plan limits and X credits apply, and thread reservations happen before sending. These are exactly the operational traits an agent needs to avoid incorrect invocation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The opening is front-loaded and the content is relevant, but the description is a very dense block covering many edge cases, plan limits, trial offers, and platform quirks. It is informative but not concise; an agent must parse a wall of text to reach later operational details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 11 parameters, nested per_platform objects, many platforms, and no output schema, the description is remarkably complete. It explains the return shape, platform-specific media rules, approval behavior, credit and limit handling, and thread status semantics — enough for an agent to call and interpret the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already carries most parameter meaning. The description still adds valuable cross-parameter constraints not fully captured in the schema, such as YouTube requiring video_url, TikTok requiring video_url or photos, multi-item carousel behavior, and X thread/reply credit rules.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource — 'Publishes a post immediately and publicly' — and the word 'immediately' distinguishes it from the scheduling siblings such as schedule_post and bulk_schedule. It is clear what the tool does without needing to inspect the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives strong usage context: immediate publishing, public visibility, per-platform media requirements, duplicate refusal, brand ambiguity, approval holds, and API-key limits. It stops short of explicitly naming the alternative tool for scheduling, but the immediate-publish framing makes the when-to-use boundary clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.