AdaptlyPost
Server Details
Post + analytics: Instagram, TikTok, YouTube, X, Facebook, LinkedIn, Pinterest, Threads, Bluesky
- Status
- Healthy
- Uptime
- 93.2% over 61 days
- OAuth
- Works in Glama
- Last Tested
- Transport
- Streamable HTTP · MCP 2025-11-25
- URL
TDQS
Scored across 58 tools
Tools are partitioned into clear domains (posts, recurring, RSS, webhooks, analytics, accounts, media, AI, workspaces) and descriptions explicitly cross-reference siblings, e.g. list_posts vs get_post vs list_post_results vs list_post_analytics. A few near-neighbors remain easy to confuse at a glance: create_post vs bulk_schedule_posts vs validate_post/validate_bulk_posts, upload_media vs get_upload_urls vs get_upload_ticket, and list_top_posts vs list_post_analytics.
Names are uniformly snake_case verb_noun: list_*, get_*, create_*, update_*, delete_*, pause_*/resume_*, validate_*, upload_*, trigger_*, retry_*. Minor outliers like bulk_schedule_posts, publish_draft, retry_failed_platforms and open_upload_widget still follow the same readable verb+object convention.
58 tools far exceeds a practical surface for one server, even though the stated scope spans publishing, recurring posts, RSS, webhooks, analytics, media upload, AI and workspaces. Several tools are thin wrappers (test_webhook, get_upload_ticket, check_account, check_rss_feed) that individually earn little place, and the volume raises selection cost for an agent.
Coverage is broad and near-complete: post CRUD plus scheduling/publish/unschedule/retry, bulk and validation dry-runs, RSS and webhook full lifecycles, analytics totals/timeseries/breakdown/per-post, media upload paths and account/workspace introspection. Gaps are mostly by design: recurring series cannot be created or edited directly (only via create_post recurrence; editing only in the app), and there is no account-refresh/update beyond check_account for Facebook.
Available Tools
58 toolsbulk_schedule_postsBulk Schedule PostsADestructiveInspect
Schedule up to 100 posts in one call to the same platforms and accounts. Each item supplies its own text, contentType, scheduledAt, and optional media; platforms, connection-id arrays, timezone, and platform configs are shared by every item, though an item may carry its own tiktokConfigs, youtubeConfigs, instagramConfigs, facebookConfigs, pinterestConfigs, googleBusinessConfigs or tumblrConfigs to replace the shared ones, plus its own firstComments, threadReplies, platformThumbnails and platformAspectRatios. twitterKeepLinks and linkedinConfigs are not available in bulk. Call validate_bulk_posts with the same input first to see the problems of every item without creating anything. Items are processed independently: each is validated and created like create_post, so one bad item fails alone while the rest are scheduled. Returns { totalScheduled, totalFailed, results[] } with a postId or errorMessage per item, in input order; read every row. An item with a past scheduledAt publishes immediately rather than being rejected. Call list_accounts first; TikTok needs tiktokConfigs with privacyLevel, and Pinterest takes pinterestConfigs with a boardId from list_pinterest_boards or a boardName, not both; an item whose boardName matches no board or several fails alone. Use create_post for a single post or a draft; this tool has no draft mode. These posts publish publicly to the user's social accounts: show the user every item's text, media and time plus the accounts, and get their confirmation before calling. Each call creates new posts, so calling again after an error or timeout can publish duplicates; check list_posts first.
| Name | Required | Description | Default |
|---|---|---|---|
| posts | Yes | 1 to 100 posts to schedule; each is created independently | |
| pageIds | No | Facebook page account ids from list_accounts (the account id; its pageId value is also accepted). Facebook has no connection-id array | |
| timezone | No | IANA timezone stored with every post for display; does not shift scheduledAt | UTC |
| platforms | Yes | Target platforms shared by every item. Each needs its connection-id array (pageIds for FACEBOOK, googleBusinessConnectionIds for GOOGLE_BUSINESS) | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another | |
| tiktokConfigs | No | TikTok per-connection config. Each entry needs connectionId + privacyLevel at minimum | |
| tumblrConfigs | No | Tumblr per-blog config: tags, a title and a source link. connectionId must match an entry in tumblrConnectionIds | |
| youtubeConfigs | No | YouTube per-connection config with video title, tags, privacy, etc. | |
| facebookConfigs | No | Facebook per-page config: post type, shareToStory, video title, text background, and a grid or link carousel for several images. pageId must match an entry in pageIds | |
| instagramConfigs | No | Instagram per-connection config: post type (FEED, REEL, STORY), shareToStory, collaborators, user tags, the AI info label, Reel audio, and trial reels | |
| pinterestConfigs | No | Pinterest per-connection config: the board to pin to, a pin title and a destination link. Get boardId from list_pinterest_boards for that connectionId, or pass the board name as boardName instead (not both); a board belongs to one Pinterest account. A boardName that matches no board or several fails with 400. Without either the pin goes to a board named AdaptlyPost | |
| tiktokConnectionIds | No | TikTok account connection IDs to post from | |
| tumblrConnectionIds | No | Tumblr blogs to post to, by the account id from list_accounts. TUMBLR takes text up to 32768 characters, up to 30 JPEG, PNG or GIF images (10 MB each) or one MP4 video (500 MB, up to 10 minutes), and alt text; it has no first comments, threads, per-platform thumbnails, image shapes or analytics | |
| blueskyConnectionIds | No | Bluesky account connection IDs to post from | |
| threadsConnectionIds | No | Threads account connection IDs to post from | |
| twitterConnectionIds | No | X (Twitter) account connection IDs to post from | |
| youtubeConnectionIds | No | YouTube channel connection IDs to post from | |
| googleBusinessConfigs | No | Google Business Profile per-location config: update, event or offer, plus a button. connectionId must match an entry in googleBusinessConnectionIds. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters | |
| linkedinConnectionIds | No | LinkedIn account connection IDs to post from | |
| mastodonConnectionIds | No | Mastodon account connection IDs to post from | |
| telegramConnectionIds | No | Telegram channels and groups to post to, by the account id from list_accounts. TELEGRAM takes text up to 4096 characters, up to 10 images (JPEG, PNG or WebP, 10 MB each) or one MP4 or MOV video (50 MB); a caption over 1024 characters goes out as its own message after the media | |
| instagramConnectionIds | No | Instagram account connection IDs to post from | |
| pinterestConnectionIds | No | Pinterest account connection IDs to post from | |
| googleBusinessConnectionIds | No | Google Business Profile locations to post to, by the account id from list_accounts. A location without an entry in googleBusinessConfigs gets a STANDARD update |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with totalScheduled, totalFailed, and results: one { postId, success, isScheduled, scheduledAt, errorMessage } per input item, in input order. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare destructive=true, readOnly=false, and openWorld=true, but the description adds meaningful behavioral context: items are processed independently, one bad item fails alone, past scheduledAt values publish immediately, and repeated calls can create duplicates. It also discloses public publishing and requires showing every item plus accounts for confirmation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose, validation step, item failure behavior, platform constraints, confirmation requirement, and duplicate warning are front-loaded and useful. The description is dense and somewhat long for a single paragraph, with some platform details repeated from the schema, but it remains readable and appropriate for the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is complete for a complex batch mutation tool: it covers input sharing versus per-item overrides, independent processing and partial failures, validation, platform-specific requirements, draft limitations, confirmation, and duplicate risk. Since an output schema exists, it does not need to explain return formats further, though it helpfully mentions the result shape.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents parameters in detail. The description still adds useful batch-level semantics by explaining which values are shared across all items and which platform configs can be overridden per item, plus limitations such as twitterKeepLinks and linkedinConfigs being unavailable in bulk.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the specific verb and resource: scheduling up to 100 posts in one call. It also distinguishes the batch operation from create_post and validate_bulk_posts, so an agent can tell when this tool is the correct choice.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit routing guidance: call validate_bulk_posts first, use create_post for a single post or draft, call list_accounts first, and use list_posts before retrying after errors. It also states that this tool has no draft mode and requires user confirmation before publishing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_accountCheck AccountAIdempotentInspect
Re-check a Facebook page with Facebook now, using its stored token, and return its fresh status. A rejected token marks the page unauthorized (unauthorizedReason carries Facebook's message); a working token clears an earlier unauthorized mark. Facebook pages only: any other account fails with 400. Pages are also checked automatically twice a day. Use it after the user reconnects or fixes a page, or when a Facebook post failed with a token error. Needs the accounts.manage permission, which Admin holds. Nothing is posted.
| Name | Required | Description | Default |
|---|---|---|---|
| accountId | Yes | The Facebook account id from list_accounts, or its pageId | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with id, platform, displayName, pageId, status (active or unauthorized), unauthorizedReason when unauthorized, and checkedAt. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: discloses the external Facebook call, that a rejected token sets unauthorizedReason with Facebook's message, that a working token clears an earlier mark, the 400 failure for non-Facebook accounts, the accounts.manage permission requirement, the twice-daily automatic check, and that nothing is posted. Idempotency is already in annotations, so it's not repeated needlessly.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then failure semantics, scope, triggers, and prerequisites in a compact sequence. Every sentence adds decision-relevant information with no padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Output schema exists so return values need no explanation; the description instead covers side effects, permission requirements, failure modes, eligibility, and automation cadence. Nothing an agent needs to invoke this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so accountId (id or pageId) and workspaceId are already fully documented in the schema. The description adds context about the stored token but no additional parameter syntax or constraint detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: re-check a Facebook page live with its stored token and return fresh status. It is clearly distinguished from siblings like retry_failed_platforms or list_accounts by naming the re-verification behavior and the Facebook-only scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit triggers: after the user reconnects or fixes a page, or when a Facebook post failed with a token error. It does not name an alternative tool that might also resolve token errors (e.g. retry_failed_platforms), so the when-not/alternative guidance is incomplete rather than absent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_rss_feedCheck RSS Feed NowADestructiveIdempotentInspect
Move an RSS feed's next check to now; the feed is fetched within a minute and any new items are posted according to its post mode. Use it when the user just published an article and does not want to wait for the interval. Read list_rss_feed_items a minute later to see the result. Ids outside the workspace return 404. Needs the posts.draft permission.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | RSS feed id from list_rss_feeds or create_rss_feed | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | The feed with its new nextCheckAt. The RSS feed: id, userId (the member it posts as, whoever last saved it), name, url, siteUrl, status (ACTIVE or PAUSED), pauseReason, lastError, postMode, publishDelayMinutes, contentMode, template, aiInstructions, includeImage, twitterKeepLinks, includeKeywords, excludeKeywords, maxPostsPerCheck, checkIntervalMinutes, targets, nextCheckAt, lastCheckedAt, lastPostedAt, createdAt and updatedAt. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations flag destructiveHint=true and openWorldHint=true; the description adds that the fetch causes new items to be posted according to post mode, which is the concrete side effect an agent needs to understand before triggering. It also discloses the posts.draft permission requirement and 404 behavior for foreign ids. Only missing detail is whether the reschedule is reversible/undoable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short, front-loaded sentences: action, side effect, when to use, verification step, error case, permission. Each sentence carries distinct information with no repetition of the name or title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be explained. The description still covers timing, side effects, error behavior, follow-up, and permissions, leaving nothing material for an agent to guess before invoking.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both id and workspaceId are already documented in the schema, including sourcing and workspace consistency rules. The description adds only the 404 behavior for out-of-workspace ids, which is marginal incremental value over the schema baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Move an RSS feed's next check to now') with immediate effect spelled out (fetched within a minute, items posted per post mode). This clearly distinguishes it from pause_rss_feed, resume_rss_feed, and preview_rss_feed siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names the triggering situation ('when the user just published an article and does not want to wait for the interval') and the follow-up action ('Read list_rss_feed_items a minute later'). This gives when-to-use, an alternative-avoidance rationale, and the next step.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_connect_linkCreate Connect LinkAInspect
Create a link someone else, such as a client, opens to connect their social accounts to this workspace without an AdaptlyPost login. With no options it is a quick link: it lasts 7 days, offers every platform, shows the client every account in the workspace and connects any number of accounts. visibility PRIVATE shows the client only the accounts they connected through the link; allowedPlatforms limits the platforms offered; maxAccounts makes the link stop working once that many accounts are connected through it; expiresAt or neverExpires changes when it stops working. Returns the url to send. Connected accounts then show up in list_accounts. Revoke it with revoke_connect_link. Needs the accounts.manage permission, which Admin holds.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Label shown in the dashboard list of links (max 80 characters) | |
| expiresAt | No | When the link stops working, as an ISO 8601 date-time with a Z or ±hh:mm offset (e.g. "2026-11-30T23:59:59Z"). At least 1 hour and at most 365 days from now. Defaults to 7 days from now. Leave it out when neverExpires is true | |
| visibility | No | PRIVATE shows the client only the accounts they connected through this link. Defaults to PUBLIC | |
| maxAccounts | No | Accounts the link can connect in total. Reconnecting an account it already connected does not count again | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another | |
| neverExpires | No | true keeps the link working until it is revoked or reaches maxAccounts. Cannot be combined with expiresAt | |
| allowedPlatforms | No | Platforms the client can pick. Omit or send [] for every platform |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with url (the link to send), token (pass it to revoke_connect_link), expiresAt (null when it never expires), name, visibility, allowedPlatforms and maxAccounts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: 7-day default lifetime, 1-hour-to-365-day bounds, that connected accounts surface in list_accounts, the returned url, and the required accounts.manage permission (and that Admin holds it). These are exactly the operational facts an agent needs before calling a non-destructive write.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the purpose, then packs the default behavior and each option into a tight sequence of sentences. No filler and no repetition of schema-only details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Output schema covers return values, and the description still states it returns the url. With annotations covering safety and the description covering lifetime, permissions, and follow-up tools, an agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds behavioral meaning: PRIVATE limits what the client sees, allowedPlatforms limits what is offered, and maxAccounts makes the link stop working after that many connections. That is useful semantics layered over the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (create a connect link) plus the exact scenario: a client connecting social accounts without an AdaptlyPost login. It also names the related tools (list_accounts, revoke_connect_link), so an agent can distinguish it from unrelated create_* siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains the no-option default case and what each option changes, and points to revoke_connect_link for teardown. It stops short of explicitly saying when to use a different tool for connecting accounts, but the context is otherwise clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_postCreate PostADestructiveInspect
Create one post on the user's own connected social accounts. saveAsDraft saves a DRAFT and publishes nothing; a scheduledAt sent with it becomes the draft's planned date, which publish_draft later schedules. Without saveAsDraft, a future scheduledAt schedules the post; otherwise it publishes now. Before publishing or scheduling, show the user the final text, media, accounts and time (or repeat schedule) and get their confirmation; a draft needs no confirmation. Account ids come from list_accounts (pass them as accountIds, or as platforms plus the per-platform arrays) and mediaUrls from upload_media. Platform-specific options (TikTok privacy, Pinterest board, LinkedIn document or reshare, Google Business event or offer, Tumblr tags, Instagram user tags, Facebook link carousel, first comments, threads of replies, recurrence) are described on each field. To find every problem before creating anything, call validate_post with the same input first. Publishing runs per platform in the background, so the response ({ postId, queuedPlatforms, isScheduled, scheduledAt }) is not the outcome; check list_post_results. Each call creates a separate post, so after an error or timeout check list_posts before trying again. Use update_post or publish_draft for an existing post and bulk_schedule_posts for many posts.
| Name | Required | Description | Default |
|---|---|---|---|
| text | No | Default post text shared across platforms. On LinkedIn, mention a company page with @[Page Name](urn:li:organization:<id>), using the page name exactly as LinkedIn shows it | |
| pageIds | No | Facebook page account ids from list_accounts (the account id; its pageId value is also accepted). Facebook has no connection-id array | |
| timezone | No | IANA timezone stored with the post for display (e.g. "America/New_York"); it does not shift scheduledAt | UTC |
| mediaUrls | No | Media URLs to attach. Use publicUrl values from upload_media or get_upload_urls; the same publicUrl may be reused across posts. Do not reuse mediaUrls read back from a published post, which may be expiring platform links | |
| platforms | No | Target platforms (e.g. ["LINKEDIN", "TWITTER"]). Each one needs its matching connection-id array (pageIds for FACEBOOK, googleBusinessConnectionIds for GOOGLE_BUSINESS) filled with ids from list_accounts. Optional when accountIds is sent | |
| accountIds | No | Account ids (or Facebook pageIds) from list_accounts to post to. AdaptlyPost adds each account's platform to platforms and its id to the matching connection-id array, so you can send these instead of platforms and the per-platform arrays, or alongside them. An id not connected to the workspace fails with 400 | |
| recurrence | No | Repeat the post on a schedule the user asked for, and confirm that schedule with them first. Needs a future scheduledAt, which becomes the first post and sets the time of day in timezone. Cannot be combined with saveAsDraft or TIKTOK. Missed slots, for example while paused, are skipped and never published late. The user can pause or stop the series at any time with pause_recurring_post or delete_recurring_post; list_recurring_posts shows it | |
| contentType | Yes | Content type: TEXT, IMAGE, VIDEO, CAROUSEL, or DOCUMENT. Must match mediaUrls. CAROUSEL takes 2 or more items in mediaUrls, up to 4 on TWITTER, BLUESKY and MASTODON, 5 on PINTEREST, 10 on INSTAGRAM, FACEBOOK, THREADS and TELEGRAM, 20 on LINKEDIN, 30 on TUMBLR and 35 on TIKTOK (JPEG or WebP photos only). INSTAGRAM and THREADS accept images and videos in the same carousel; every other platform takes images only, and YOUTUBE has no carousel. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters. TELEGRAM takes text up to 4096 characters, up to 10 images (JPEG, PNG or WebP, 10 MB each) or one MP4 or MOV video (50 MB); a caption over 1024 characters goes out as its own message after the media. DOCUMENT publishes one PDF, PPT, PPTX, DOC or DOCX file (max 100 MB, 300 pages) as a LinkedIn document post and is LinkedIn only: put exactly that one file in mediaUrls, target only LINKEDIN, and set the title with linkedinConfigs | |
| saveAsDraft | No | Save as DRAFT instead of publishing or scheduling; publish later with publish_draft. A scheduledAt sent with it is stored as the draft's planned date, and publish_draft schedules the draft for that date | |
| scheduledAt | No | Absolute ISO 8601 instant to schedule (e.g. "2026-03-15T10:00:00Z"). Omit to post immediately; a past time also posts immediately. With saveAsDraft it is the draft's planned date instead: nothing is scheduled, and publish_draft without a date later schedules the draft for it | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another | |
| thumbnailUrl | No | Video thumbnail as an https URL or an image data URI, used on every platform that takes one unless platformThumbnails overrides it | |
| firstComments | No | A comment posted from the same account right after the post goes out on a platform, one entry per platform. Available on LINKEDIN (1250 characters), TWITTER (280, as a reply), THREADS (500, as a reply), BLUESKY (300, as a reply), MASTODON (500, as a reply), YOUTUBE (10000), FACEBOOK (8000) and INSTAGRAM (2200). A platform the post does not go to, an empty or too long comment, a second entry for one platform, a platform that also has threadReplies, a private or made for kids YouTube video and Facebook or Instagram stories are refused with 400. The comment is posted about 10 seconds after the platform publishes (60 on YouTube) and retried up to 3 times; on X it is not retried, and a lifetime-deal account pays for it like any X post. A Facebook Page or Instagram account connected before first comments came to them must be reconnected once; until then its comment fails and firstCommentError says to reconnect. A comment that fails never fails the post: read firstCommentStatus and firstCommentError on the platform in get_post. On an update, sending the array replaces every first comment and omitting it keeps the stored ones | |
| mediaAltTexts | No | Alt text per image, in the same order as mediaUrls (max 1000 characters each; use "" to skip an image). Sent to X, Bluesky, Mastodon, Tumblr, LinkedIn, Facebook, Instagram and Threads; Pinterest uses the first one (cut to 500). TikTok, YouTube, Google Business Profile and videos ignore it | |
| platformTexts | No | Per-platform caption overrides | |
| threadReplies | No | Turns the post into a thread: the post opens it and each text is published as a reply to the one before, from the same account, one entry per platform. Available on TWITTER (280 characters per reply, or the account's own limit on X Premium), THREADS (500), BLUESKY (300) and MASTODON (500, or the instance's limit), up to 25 replies. A platform the post does not go to, an empty or too long reply, more than 25 replies, a second entry for one platform and a platform that also has a first comment are refused with 400. An entry with an empty texts array removes the thread. Replies start about 10 seconds after the platform publishes, 2 seconds apart. A failed run is retried up to 3 times and resumes after the last reply that went out; on X it is not retried, and a lifetime-deal account pays for each reply like any X post. A thread that fails never fails the post: read threadStatus, threadReplyIds and threadError on the platform in get_post. On an update, sending the array replaces every thread and omitting it keeps the stored ones | |
| tiktokConfigs | No | TikTok per-connection config. Each entry needs connectionId + privacyLevel at minimum | |
| tumblrConfigs | No | Tumblr per-blog config: tags, a title and a source link. connectionId must match an entry in tumblrConnectionIds | |
| youtubeConfigs | No | YouTube per-connection config with video title, tags, privacy, etc. | |
| facebookConfigs | No | Facebook per-page config: post type, shareToStory, video title, text background, and a grid or link carousel for several images. pageId must match an entry in pageIds | |
| linkedinConfigs | No | LinkedIn per-connection config: documentTitle names a DOCUMENT post, reshareOf reshares another LinkedIn post with the text as commentary. connectionId must match an entry in linkedinConnectionIds | |
| instagramConfigs | No | Instagram per-connection config: post type (FEED, REEL, STORY), shareToStory, collaborators, user tags, the AI info label, Reel audio, and trial reels | |
| pinterestConfigs | No | Pinterest per-connection config: the board to pin to, a pin title and a destination link. Get boardId from list_pinterest_boards for that connectionId, or pass the board name as boardName instead (not both); a board belongs to one Pinterest account. A boardName that matches no board or several fails with 400. Without either the pin goes to a board named AdaptlyPost | |
| twitterKeepLinks | No | Keep links in the X text clickable. X charges over 10 times more for a post with a link, so by default every link in X text is broken (example.com becomes example. com). Only AppSumo lifetime deals can turn this on, and a kept link costs 20 credits instead of 2. true on any other plan is refused with 400; it is ignored when the X text has no link | |
| platformThumbnails | No | A different thumbnail for one platform of a VIDEO post, one entry per platform. A platform without an entry uses the post-level thumbnailUrl and thumbnailTimestampMs. YOUTUBE, FACEBOOK, LINKEDIN and TELEGRAM take an image (thumbnailUrl); INSTAGRAM and PINTEREST take an image or a frame (thumbnailTimestampMs), the image winning when both are sent; TIKTOK takes only a frame. Posts that are not videos, Facebook and Instagram stories, a second entry for one platform and an entry the platform cannot use are refused with 400. On an update, sending the array replaces every override and omitting it keeps the stored ones | |
| tiktokConnectionIds | No | TikTok account connection IDs to post from | |
| tumblrConnectionIds | No | Tumblr blogs to post to, by the account id from list_accounts. TUMBLR takes text up to 32768 characters, up to 30 JPEG, PNG or GIF images (10 MB each) or one MP4 video (500 MB, up to 10 minutes), and alt text; it has no first comments, threads, per-platform thumbnails, image shapes or analytics | |
| blueskyConnectionIds | No | Bluesky account connection IDs to post from | |
| platformAspectRatios | No | Reframe every image of an IMAGE or CAROUSEL post to one shape on a platform, one entry per platform. INSTAGRAM takes SQUARE, PORTRAIT or LANDSCAPE (Instagram refuses 9:16 feed and carousel images); TIKTOK takes all four. Video posts, Instagram stories and a second entry for the same platform are refused with 400. Omit a platform to keep its images as uploaded. On an update it applies to the mediaUrls sent in the same request | |
| threadsConnectionIds | No | Threads account connection IDs to post from | |
| thumbnailTimestampMs | No | Video frame timestamp (ms) to use as the thumbnail, used by INSTAGRAM, PINTEREST and TIKTOK unless platformThumbnails overrides it | |
| twitterConnectionIds | No | X (Twitter) account connection IDs to post from | |
| youtubeConnectionIds | No | YouTube channel connection IDs to post from | |
| googleBusinessConfigs | No | Google Business Profile per-location config: update, event or offer, plus a button. connectionId must match an entry in googleBusinessConnectionIds. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters | |
| linkedinConnectionIds | No | LinkedIn account connection IDs to post from | |
| mastodonConnectionIds | No | Mastodon account connection IDs to post from | |
| telegramConnectionIds | No | Telegram channels and groups to post to, by the account id from list_accounts. TELEGRAM takes text up to 4096 characters, up to 10 images (JPEG, PNG or WebP, 10 MB each) or one MP4 or MOV video (50 MB); a caption over 1024 characters goes out as its own message after the media | |
| instagramConnectionIds | No | Instagram account connection IDs to post from | |
| pinterestConnectionIds | No | Pinterest account connection IDs to post from | |
| googleBusinessConnectionIds | No | Google Business Profile locations to post to, by the account id from list_accounts. A location without an entry in googleBusinessConfigs gets a STANDARD update |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with postId, queuedPlatforms (platforms whose publishing job was queued; empty for scheduled posts and drafts), skippedPlatforms, isScheduled, and scheduledAt, plus recurringPostId when recurrence was sent. Publishing is asynchronous: check list_post_results for outcomes. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint and openWorldHint but say nothing operational; the description adds the crucial non-obvious traits: publishing runs per platform in the background so the response is not the outcome (check list_post_results), each call creates a separate post so check list_posts after an error or timeout before retrying, and confirmation must precede any live or scheduled publish. That is exactly the idempotency and confirmation context an agent needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: purpose, then draft-vs-schedule semantics, then confirmation, then inputs, then validation and retry guidance. For a 40-parameter tool this length is largely earned, though a few clauses (e.g. the pointer that platform options are 'described on each field') are meta-filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 40 parameters, nested configs and an output schema, the description covers everything an agent needs to act correctly: prerequisites (list_accounts, upload_media), pre-flight validation, confirmation policy, async outcome handling, retry safety, and sibling routing. Return values are echoed briefly rather than needing explanation, which is fine since the output schema exists.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and per-field docs are extensive, so the description only needs to add cross-parameter meaning — which it does by explaining that accountIds can substitute for platforms plus the per-platform arrays, and by spelling out the scheduledAt/saveAsDraft interaction (draft planned date consumed later by publish_draft). Remaining detail is delegated to the schema, so it stops short of 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and resource ('Create one post on the user's own connected social accounts') and immediately scopes the tool to a single post, distinguishing it from publish_draft, update_post and bulk_schedule_posts by name. An agent can tell exactly which creation path this is.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use branches: saveAsDraft vs future scheduledAt vs immediate publish; validate_post first to surface all problems; update_post/publish_draft/bulk_schedule_posts for the alternatives. It also states a required human-confirmation workflow before publishing or scheduling and that drafts need none.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_rss_feedCreate RSS FeedADestructiveInspect
Connect an RSS or Atom feed so each new item becomes a post on the target accounts. The feed is fetched and every item already in it is recorded, so only items that appear later are posted; postLatestItem also posts the newest one on the first check. The feed is then checked every checkIntervalMinutes and posts as the member who saved it, as a draft, a scheduled post or straight away (postMode). With postMode SCHEDULE or PUBLISH, posts go out on the user's accounts without further confirmation, so confirm the feed, the accounts, the mode and the text with the user first. Try preview_rss_feed first to show what the posts will say. Fails with 400 for invalid settings, a URL that is not a feed, a feed already connected or the 20-feed workspace limit, and 503 when the feed cannot be reached. Needs posts.draft, plus the permission of the post mode.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Public http(s) URL of an RSS or Atom feed | |
| name | No | Name of the feed (max 120 characters). Defaults to the feed's title | |
| targets | Yes | Accounts every new item is posted to, 1 to 20. Feeds post to FACEBOOK, INSTAGRAM, THREADS, TWITTER, BLUESKY, LINKEDIN, MASTODON, TELEGRAM and GOOGLE_BUSINESS | |
| postMode | Yes | DRAFT creates a draft and needs posts.draft; SCHEDULE schedules the post publishDelayMinutes after the item is found and needs posts.schedule; PUBLISH publishes it right away and needs posts.publish | |
| template | No | Post text with {title}, {link}, {description}, {author} and {feed} (max 2000 characters, default "{title}\n\n{link}"). The description, then the title, is shortened to fit each platform; the link is never cut | |
| contentMode | Yes | TEMPLATE fills template; AI writes one caption per platform from the article, appends the link, spends 1 AI credit per platform per item and needs ai.generate | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another | |
| includeImage | No | Attach the item's image, or the article's preview image (default true) | |
| aiInstructions | No | Extra instructions for AI captions (max 1000 characters) | |
| postLatestItem | No | Also post the newest item on the first check (default false) | |
| excludeKeywords | No | Skip items whose title or summary contains one of these (up to 50) | |
| includeKeywords | No | Post only items whose title or summary contains one of these (up to 50) | |
| maxPostsPerCheck | No | New items posted per check, 1 to 10 (default 3). New items are posted oldest first; the rest wait for the next check | |
| twitterKeepLinks | No | Keep links in X posts clickable (default false). Lifetime-deal plans only; each X post with a link then costs more credits. Without it, links on X go out as plain text | |
| publishDelayMinutes | No | Minutes between finding an item and its post going out, 5 to 10080. Required when postMode is SCHEDULE | |
| checkIntervalMinutes | No | Minutes between checks: 15, 30, 60 (default), 180, 360, 720 or 1440 |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | The new feed. The RSS feed: id, userId (the member it posts as, whoever last saved it), name, url, siteUrl, status (ACTIVE or PAUSED), pauseReason, lastError, postMode, publishDelayMinutes, contentMode, template, aiInstructions, includeImage, twitterKeepLinks, includeKeywords, excludeKeywords, maxPostsPerCheck, checkIntervalMinutes, targets, nextCheckAt, lastCheckedAt, lastPostedAt, createdAt and updatedAt. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already mark this as destructive and open-world, and the description adds substantial context: existing items are recorded so only later items post, postLatestItem changes first-check behavior, checks repeat on checkIntervalMinutes, and SCHEDULE/PUBLISH publish without further confirmation. It also discloses specific 400 and 503 failure conditions and required permissions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and key behavior are front-loaded in the first sentence, and nearly every sentence adds operationally important information about scheduling, confirmation, preview, errors, and permissions. It is dense but appropriate for a 16-parameter mutation tool, though bullets or shorter sentences could improve scanability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the 16 parameters, destructive/open-world annotations, and an output schema, the description is complete enough for an agent to call the tool correctly. It covers setup behavior, ongoing checks, confirmation requirements, alternatives, permissions, and failure modes.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the input schema already documents every parameter in detail, including enums, defaults, limits, and permission implications. The description reinforces the risk of postMode and the first-check behavior of postLatestItem, but it largely repeats rather than adding new parameter-specific semantics beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: connect an RSS or Atom feed so new items become posts on target accounts. It clearly distinguishes this creation tool from preview_rss_feed and the update/delete/list siblings by describing the ongoing posting behavior.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly recommends preview_rss_feed first and warns to confirm the feed, accounts, mode, and text with the user before SCHEDULE or PUBLISH. It also states the required permission scope and explains when errors such as duplicate feeds or workspace limits occur.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_webhookCreate WebhookAInspect
Register a URL that receives every workspace event as an HTTP POST: post.published, post.partially_failed, post.failed, post.scheduled, account.unauthorized, image.completed and image.failed. Each delivery carries the x-adaptly-signature, x-adaptly-timestamp, x-adaptly-event and x-adaptly-webhook-id headers; the signature is sha256=HMAC_SHA256(secret, "{timestamp}.{rawBody}"). Failed deliveries are retried up to 5 times with exponential backoff, and an endpoint is turned off after 20 failed deliveries in a row. The response is the only time the signing secret is shown, so give it to the user to store. Fails with 400 for an invalid URL or the webhook limit, and 409 when the URL is already registered. Needs the webhooks.manage permission, which Admin and Editor hold.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Publicly reachable http(s) endpoint that receives every event | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | The new webhook plus secret, the signing secret shown only this once. The webhook: id, url, active, createdAt, updatedAt, lastSuccessAt, lastFailureAt and disabledAt (set when it was turned off after 20 failed deliveries in a row). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the annotations (readOnlyHint=false, openWorldHint=true, destructiveHint=false) by disclosing delivery headers, the exact HMAC signature construction, retry policy (5 attempts, exponential backoff), auto-disable after 20 consecutive failures, and the one-time-display property of the signing secret. It also names the failure modes (400 invalid URL/limit, 409 duplicate URL), which an agent needs to handle rather than guess at.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in the first clause, and the dense remainder is all operational payload rather than repetition. It is a long, unstructured block, but virtually every sentence carries non-obvious information an agent would otherwise have to discover by error.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, yet the description still surfaces the single most important return-value fact — that the response is the only time the signing secret is exposed. Combined with error codes and permission requirements, an agent can call this correctly with no further context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters are already documented in structured form and the baseline is 3. The description adds only marginal parameter meaning — that the registered URL receives every event, and that an invalid URL yields 400 — while workspaceId scoping is left entirely to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and resource — "Register a URL that receives every workspace event as an HTTP POST" — and enumerates the exact event types delivered. This separates it unambiguously from sibling lifecycle tools like update_webhook, test_webhook, and list_webhooks.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It establishes the trigger (registering a new endpoint), the prerequisite permission (webhooks.manage, held by Admin and Editor), and the caller's follow-up duty (hand the secret to the user because it is shown only once). It stops short of explicitly routing to siblings, e.g. saying to use update_webhook for an existing endpoint rather than registering a duplicate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_postDelete PostADestructiveInspect
Delete a post record from AdaptlyPost by id. Use it to cancel a DRAFT or SCHEDULED post before it goes out; a deleted scheduled post will not publish. Deleting never removes content already on a network: for a COMPLETED or PARTIAL_FAILURE post this only drops AdaptlyPost's record, and the live posts stay up until removed on each platform. Prefer update_post to change a post instead of deleting and recreating it. A post in PUBLISHING fails with 409; wait for list_post_results to settle. Only posts in the workspace (the current one unless workspaceId names another) can be deleted; others return "Post not found or access denied". Returns { deleted: true }. Irreversible.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Post ID to delete, from list_posts or create_post | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with deleted: true once the post record is removed from AdaptlyPost. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=true, but the description goes well beyond them: it clarifies that deletion only drops AdaptlyPost's record while live COMPLETED/PARTIAL_FAILURE posts stay up, discloses the 409 state conflict, the access-denied response for out-of-workspace posts, and that the operation is irreversible.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and use case, then layered with edge cases and constraints; nearly every sentence earns its place. The 'Returns { deleted: true }' line is redundant given an output schema exists, a minor efficiency loss.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive mutation tool this is complete: state-dependent behavior, error handling, access-control semantics, sibling alternative, and irreversibility are all covered, and the output schema carries return details.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds meaning on top of the schema by stating the workspace scoping consequence ('Only posts in the workspace... others return "Post not found or access denied"'), which the schema does not express.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clear specific verb + resource ('Delete a post record from AdaptlyPost by id') with the exact scope of what is affected. It explicitly names the sibling alternative (update_post) and distinguishes cancel-before-publish from removing live content.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use (cancel DRAFT/SCHEDULED before it goes out), when-not (prefer update_post instead of delete/recreate), plus the state-specific failure condition (PUBLISHING returns 409; wait for list_post_results). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_recurring_postDelete Recurring PostADestructiveInspect
Delete a recurring post: the series stops for good and its upcoming SCHEDULED post is deleted. Posts that already went out are kept. Prefer pause_recurring_post when the user may want the series back. To skip a single date, delete that occurrence with delete_post instead; the series continues. Ids outside the workspace (the current one unless workspaceId names another) return "Recurring post not found". Returns { deleted: true }. Irreversible.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Recurring post ID to delete, from list_recurring_posts | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with deleted: true once the recurring post is removed. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, and the description goes further by specifying exactly what is destroyed (series + upcoming scheduled post, past posts retained), that the action is irreversible, and that out-of-workspace ids return "Recurring post not found". It also reports the return shape ({ deleted: true }). Rates just under 5 only because it omits permission/auth requirements and any cascade effects on analytics or linked drafts.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the destructive consequence and then layers routing guidance, error behaviour, return value, and irreversibility in short declarative clauses. No sentence is filler, despite covering a lot of ground.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive two-parameter tool with an output schema present, the description supplies everything the agent needs: scope of deletion, irreversibility, sibling routing, and error semantics. Return-value explanation is redundant with the output schema but harmless.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both id and workspaceId are already documented, giving a baseline of 3. The description adds meaning beyond that by explaining the workspace-scoping consequence tied to workspaceId (ids outside the current workspace yield "Recurring post not found"), which helps the agent reason about cross-workspace misuse.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Delete) and resource (recurring post), and immediately defines the scope of the deletion: the whole series stops permanently and the upcoming scheduled post is removed while already-published posts are kept. It distinguishes itself from the near neighbours delete_post and pause_recurring_post by name without the agent needing to open their schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit routing rules in both directions: prefer pause_recurring_post when the user might want the series back, and use delete_post to skip a single occurrence so the series continues. It effectively covers when-to-use and when-not-to-use with the alternatives named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_rss_feedDelete RSS FeedADestructiveInspect
Delete an RSS feed: it stops being checked for good. Posts it already created stay. Prefer pause_rss_feed when the user may want it back. Ids outside the workspace return 404. Needs the posts.draft permission. Returns { deleted: true }. Irreversible.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | RSS feed id from list_rss_feeds or create_rss_feed | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with deleted: true once the feed is removed. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the destructiveHint annotation, it discloses what survives (previously created posts), the error behavior for out-of-workspace ids (404), the required permission (posts.draft), and the response payload. That is the full behavioral picture an agent needs before an irreversible write.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Six short clauses, front-loaded with purpose and preference, then constraints. Every sentence carries distinct decision-relevant information with no repetition of the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter destructive delete, the description covers consequence, alternative, permission, edge-case error, and return value; the output schema exists so return detail is not required. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both id and workspaceId are already documented, and the description does not restate their formats. It only adds indirect guidance via 'Ids outside the workspace return 404', which reinforces workspace scoping but does not explain the parameters themselves.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Delete an RSS feed') plus the operational consequence ('it stops being checked for good'), which immediately separates it from pause_rss_feed. An agent can distinguish it from all listed siblings without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Prefer pause_rss_feed when the user may want it back' names the alternative and the exact condition that selects it, and 'Irreversible' closes the decision. No exclusions or prerequisites are left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_webhookDelete WebhookADestructiveInspect
Delete a webhook endpoint; it receives nothing more. Use update_webhook with active: false to pause it instead. Needs the webhooks.manage permission. Returns { deleted: true }. Irreversible.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Webhook id from list_webhooks or create_webhook | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with deleted: true once the webhook is removed. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and readOnlyHint=false, and the description adds context beyond them: the exact permission needed (webhooks.manage), that the operation is irreversible, and what the endpoint stops doing. This is the kind of consequence detail an agent needs before a destructive call.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short clauses, front-loaded with the action, then the alternative, then prerequisites, then consequence. Nothing is padded and each sentence carries a distinct fact.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter destructive tool with an output schema, the description covers the alternative path, auth requirement, reversibility, and outcome. Nothing an agent needs in order to call it safely is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with both id and workspaceId fully documented including where the ids come from. The description adds nothing about parameter meaning, so the schema does all the work and baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (delete) and resource (webhook endpoint), and immediately distinguishes itself from update_webhook, the sibling an agent might confuse it with. The contrast with pausing makes the scope unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names the alternative (update_webhook with active: false) and the condition under which to prefer it, which is a genuine when-not-to-use-this-tool statement. Also states the required permission, a prerequisite no sibling list conveys.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
generate_captionGenerate CaptionAInspect
Write a new social media caption from a prompt with AdaptlyPost AI. Returns { caption }, text only; nothing is saved or posted, so pass the caption to create_post, update_post or bulk_schedule_posts yourself. Pass platform and generation targets that platform's character limit; check the returned text before posting. Needs the ai.generate permission, which Admin, Editor and Contributor hold and Viewer does not (403 permission_denied). Each call spends 2 of the member's AI credits (the member who signed in or created the key), refunded if generation fails, unless the member has their own AI provider key connected in AdaptlyPost. With no credits left the call fails: explain that generation is unavailable with the current credit balance and do not retry automatically. To rework a caption you already have, use refine_caption instead.
| Name | Required | Description | Default |
|---|---|---|---|
| prompt | Yes | What the caption should say or be about, including tone, audience, hashtags or a call to action (max 2000 characters) | |
| platform | No | Platform the caption is for; generation targets that platform's character limit; check the returned text before posting. Omit for a general caption | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with caption: the generated text. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes far beyond the annotations: nothing is persisted or posted, requires ai.generate, names the roles that hold it (Admin/Editor/Contributor, not Viewer) with the exact 403 permission_denied code, and discloses the 2-credit cost per call, refund-on-failure, the bring-your-own-key exemption, and the no-credit failure path with 'do not retry automatically'.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads what it does and what it returns, then layers permissions, credits and failure handling in a logical order with no filler sentences. It is a dense block, but nearly every clause carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, yet the description still names the return shape and, more importantly, covers the cost, auth, quota-exhaustion and no-side-effect semantics an agent needs before calling a generation endpoint. Nothing material is left to inference.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so prompt, platform and workspaceId are already fully documented in the schema — the platform character-limit line is essentially restated. The description adds no semantics beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Write a new social media caption from a prompt') plus the exact return shape ({ caption }, text only). It also separates itself from the two nearest siblings: the post-creation tools it feeds and refine_caption for reworking existing text.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says the output must be passed to create_post, update_post or bulk_schedule_posts yourself, and names refine_caption as the alternative for reworking an existing caption. The instruction to check returned text against the platform character limit before posting is a concrete when-to-use caveat.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
generate_imageGenerate ImageAInspect
Create an image from the user's prompt with AdaptlyPost AI and save it to the user's own AI image studio in AdaptlyPost. Nothing is posted. It returns { jobId, sessionId, status } right away with status queued; poll get_image_job with the jobId every few seconds until status is completed or failed (usually 10 to 40 seconds). A completed job carries imageUrl, which can go straight into mediaUrls of create_post. Reuse sessionId to keep related images together. Needs the ai.generate permission, which Admin, Editor and Contributor hold and Viewer does not (403 permission_denied). Uses the member's AdaptlyPost AI credits (2 for standard, 4 for premium, none when the member connected their own image provider key) and refunds them if the job fails. With no credits left the job fails with an error saying so; tell the user and do not retry.
| Name | Required | Description | Default |
|---|---|---|---|
| model | No | standard (default, 2 credits) or premium (higher fidelity, 4 credits) | |
| prompt | Yes | What the image should show, including style and composition (max 2000 characters) | |
| quality | No | LOW, MEDIUM or HIGH rendering quality | |
| sessionId | No | Image studio session to add the image to, as returned by an earlier generate_image. Omit to start a new session | |
| aspectRatio | No | Image shape (default 1:1). Pick one that suits the target platform, e.g. 9:16 for stories and reels, 4:5 for Instagram feed, 16:9 for YouTube and X | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another | |
| referenceImages | No | Up to 5 image URLs the user provided, such as publicUrl values from upload_media, to guide the style or subject |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with jobId (pass it to get_image_job), sessionId, and status (queued). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond annotations (readOnlyHint=false, openWorldHint=true): discloses the required ai.generate permission and which roles hold it (403 permission_denied for Viewer), credit costs per model, refund-on-failure behavior, typical 10–40s latency, and that an empty-credit failure must not be retried.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and the 'nothing is posted' constraint, and every sentence carries operational information (polling, credits, permissions). It is a dense single paragraph rather than a wall of filler, though it is long enough that structure would aid scanning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter mutation tool with an output schema, it covers the full lifecycle an agent needs: async return shape, polling cadence, terminal statuses, downstream consumption, permission failure mode, and credit accounting. Nothing required to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds workflow meaning the schema lacks: sessionId is for keeping related images together across calls, and the returned imageUrl is the value that plugs into mediaUrls. It adds context beyond the field-level documentation without re-listing every enum.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Create an image from the user's prompt... save it to the user's own AI image studio') and immediately disambiguates from the sibling create_post with 'Nothing is posted.' An agent can distinguish this from publish/post tools without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: poll get_image_job with the jobId until completed/failed, feed imageUrl into create_post's mediaUrls, reuse sessionId for related images, and do not retry when credits are exhausted. Names both alternatives and the conditions that select them.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_analytics_overviewGet Analytics OverviewARead-onlyInspect
Workspace-wide performance for a date window: views, likes, comments, shares, followers, posts published, average views per post and engagement rate, each as { value, previousValue, deltaPercent } against the window of the same length just before it. Use this for "how did we do this month" questions and for follower counts. Metrics are summed over the selected platforms; partialMetrics names metrics some selected platform cannot report, and a metric no platform reports is null. Analytics cover Facebook, Instagram, Threads, TikTok, Pinterest, Bluesky, LinkedIn, YouTube, X and Google Business Profile (location impressions only, no per-post numbers); Mastodon, Telegram and Tumblr have none. Connecting an account imports its posts from the last 180 days, and analytics are kept from then on while the account stays connected, so any date range in that history can be queried. Analytics refresh every few hours (lastSyncedAt says when); if the user just published, call trigger_analytics_sync first. Use get_analytics_timeseries for a trend, get_platform_breakdown to compare platforms, and list_post_analytics for individual posts.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | End of the reporting window (ISO 8601). Must not be earlier than from | |
| from | Yes | Start of the reporting window as an ISO 8601 date or instant (e.g. "2026-08-01"). Metrics cover posts published between from and to; the comparison window is the same length immediately before from | |
| platforms | No | Restrict to these platforms; omit for every platform with analytics. MASTODON, TELEGRAM and TUMBLR have no analytics and are ignored. GOOGLE_BUSINESS reports location impressions only, with no per-post numbers | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another | |
| connectionIds | No | Restrict to these accounts, by the account id from list_accounts; omit for every account |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with views, likes, comments, shares, followers, postsCount, avgViewsPerPost and engagementRate (each { value, previousValue, deltaPercent }), partialMetrics, and lastSyncedAt. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, and the description adds substantial context beyond that: per-platform coverage gaps, partialMetrics/null semantics, the 180-day import limitation, and a refresh cadence mediated by lastSyncedAt. Not a full 5 only because pagination/response-size behavior is unaddressed, though the existence of an output schema lowers that burden.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with what the tool returns before any caveats, and every sentence carries relevant information. It is dense (a single long paragraph mixing return shape, coverage, retention and routing), so a small structural penalty is warranted, but nothing is genuinely filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only aggregate endpoint with five documented parameters and an output schema, the description covers what an agent needs: metric semantics, platform coverage limits, data freshness, and how to choose among the analytics siblings. Nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description still earns credit by explaining that the comparison window is the same length immediately before 'from' and that metrics are summed across selected platforms, which is derived behavior the schema alone does not convey. It does not add detail on connectionIds, but the schema already documents that fully.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (workspace-wide performance for a date window) and enumerates the exact metrics returned, including the { value, previousValue, deltaPercent } shape. It also names the siblings it is not (get_analytics_timeseries, get_platform_breakdown, list_post_analytics), so an agent can differentiate it without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit use case ("how did we do this month" questions, follower counts) and explicitly routes the agent to alternatives for trends, platform comparison and per-post data. It also names a precondition (call trigger_analytics_sync first if the user just published).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_analytics_sync_statusGet Analytics Sync StatusARead-onlyInspect
How fresh the analytics are, per connected account. Returns syncInProgress, lastSyncedAt, historyHorizonAt (the earliest date any account has data for; earlier dates have no data rather than zero activity) and platforms: one row per account with status (IDLE, QUEUED, SYNCING, FAILED), lastSyncedAt, lastErrorMessage, historyHorizonAt and needsAnalyticsReconnect. When needsAnalyticsReconnect is true the account was connected before analytics permissions existed and returns nothing until the user reconnects it (a connect link works); tell them, do not keep querying. Call this when numbers look stale or empty, and after trigger_analytics_sync to see the run finish. Takes only the optional workspaceId.
| Name | Required | Description | Default |
|---|---|---|---|
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with accountGroupId, syncInProgress, lastSyncedAt, historyHorizonAt, and platforms: one { platform, connectionId, accountName, status, lastSyncedAt, lastErrorMessage, historyHorizonAt, lastDiscoveryAt, needsAnalyticsReconnect } per connected account. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/non-destructive annotations by disclosing the sync state enum, the meaning of historyHorizonAt ('earlier dates have no data rather than zero activity'), lastErrorMessage, and the reconnect remediation including the instruction 'tell them, do not keep querying'. This is exactly the kind of behavioral context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose in one clause, and every subsequent sentence carries real information. The field enumeration is dense and somewhat list-like, and it partly duplicates the output schema, but nothing is wasted filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, triggers, sub-field meaning, failure states, and remediation, so an agent can both decide to call it and interpret the response. With an output schema present it need not explain return values, yet it does so usefully and consistently.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single workspaceId parameter is fully documented in the schema (id source, omission behavior, cross-workspace consistency). The description only adds 'Takes only the optional workspaceId', which is redundant, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a precise statement of what the tool reports ('How fresh the analytics are, per connected account') and enumerates the specific return fields, making it clearly distinct from get_analytics_overview and get_analytics_timeseries in intent. It stops short of explicitly naming those siblings as alternatives, so it lands at 4 rather than 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete triggers: 'Call this when numbers look stale or empty, and after trigger_analytics_sync to see the run finish' — a clear when-to-use plus an explicit companion tool. It also implicitly says when NOT to keep calling (needsAnalyticsReconnect accounts), but does not contrast with the other analytics siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_analytics_timeseriesGet Analytics TimeseriesARead-onlyInspect
Views, likes, comments, shares, followers, posts published and engagement rate bucketed by day (default), week or month across the window, for trend questions such as "how are views moving" or "when did followers jump". Returns { points } with one { date, ...metrics } per bucket; followers is the latest count at the end of the bucket, the other counters sum posts published inside it, and a metric no selected platform reports is null. Use get_analytics_overview for totals and list_post_analytics to see which posts drove a spike.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | End of the reporting window (ISO 8601). Must not be earlier than from | |
| from | Yes | Start of the reporting window as an ISO 8601 date or instant (e.g. "2026-08-01"). Metrics cover posts published between from and to; the comparison window is the same length immediately before from | |
| platforms | No | Restrict to these platforms; omit for every platform with analytics. MASTODON, TELEGRAM and TUMBLR have no analytics and are ignored. GOOGLE_BUSINESS reports location impressions only, with no per-post numbers | |
| granularity | No | DAILY (default), WEEKLY, or MONTHLY buckets | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another | |
| connectionIds | No | Restrict to these accounts, by the account id from list_accounts; omit for every account |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with points: one { date, views, likes, comments, shares, followers, postsCount, engagementRate } per bucket, in date order. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The read-only, non-destructive, closed-world behavior is already fully covered by the annotations, but the description adds genuinely non-structured semantics: followers is a snapshot at the end of each bucket, while other counters sum posts published within it; metrics unsupported by the selected platforms return null. That aggregation behavior is valuable and non-obvious. However, it doesn't address the comparison window mentioned only in the schema, nor latency or staleness of analytics data, so it falls short of the richest tier.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The three-sentence structure is deliberate: capability, return shape and aggregation semantics, then sibling routing. However, the opening sentence front-loads a long metric list before the distinguishing action, making the first read slightly dense rather than immediately front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has an output schema, so a full return contract is not required, yet the description still sketches the points array shape and per-metric aggregation rules. Combined with the explicit sibling routing and platform caveats, an agent has everything needed to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3; the schema already documents from/to inclusivity, ISO 8601, the comparison window, and per-platform caveats. The description's 'day (default), week or month' restates the granularity enum default, and its platform-ignore note duplicates the platforms schema text, so it adds little beyond what the structured fields provide.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the exact metrics (views, likes, comments, shares, followers, posts published, engagement rate) and the bucketing dimension (day/week/month), so the verb, resource, and dimensionality are all explicit. It is clearly distinguished from get_analytics_overview (totals) and list_post_analytics (per-post), which are both named with their respective purposes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives concrete selection criteria ('for trend questions such as "how are views moving" or "when did followers jump"') and names both alternatives with the condition that routes to each: overview for totals, list_post_analytics for spike attribution. An agent can choose among the three analytics tools without inspecting the schemas.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_image_jobGet Image JobARead-onlyInspect
Read the state of an image started with generate_image. Returns { jobId, sessionId, status, imageUrl, imageId, error }; status moves from queued through processing and generating to completed or failed. When completed, imageUrl is a public URL ready for mediaUrls in create_post. When failed, error says why, for example no credits left; a failed job is final, so do not poll it again. Poll every few seconds while status is queued, processing or generating, and stop after a couple of minutes. Only jobs started by the same member are visible. Needs the ai.generate permission, which Admin, Editor and Contributor hold and Viewer does not (403 permission_denied). Reading a job spends no credits.
| Name | Required | Description | Default |
|---|---|---|---|
| jobId | Yes | jobId returned by generate_image | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with jobId, sessionId, status (queued, processing, generating, completed or failed), imageUrl (null until completed), imageId, and error (null unless failed). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/destructiveHint=false, but the description adds substantial behavioral context: the status state machine, terminal failure semantics, member-scoped visibility, the ai.generate permission with 403 permission_denied and which roles hold it, and that reading spends no credits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: purpose first, then return shape, lifecycle, usage cadence, and constraints. Every sentence carries operative information, though the explicit return-value enumeration partially duplicates the output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a polling tool, the definition covers lifecycle states, terminal conditions, polling cadence, permissions, visibility scoping, and cost. With an output schema present, the return description is a bonus rather than a necessity, so nothing an agent needs to invoke this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents jobId and workspaceId in detail; schema description even repeats 'jobId returned by generate_image.' The description adds only marginal meaning (same-member visibility constraints) beyond the structured fields, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Read the state of an image started with generate_image.' It explicitly ties the tool to its sibling generate_image as the producer of the job, so an agent can distinguish polling from generation without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use (poll every few seconds while queued/processing/generating), when-to-stop (after a couple of minutes), and when-not-to-use (a failed job is final, do not poll again). It also directs the agent to consume imageUrl via create_post.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_meGet My AccessARead-onlyInspect
Describe this connection in the workspace (the current one unless workspaceId names another): whether it is an API key or a sign-in, its role, the permission keys it holds, can { draft, schedule, publish } and a one-sentence summary of what it may do. An API key never holds more than the member who created it (issuerRole). Call this before an action the role may not allow, instead of trying and reading a 403. Takes only the optional workspaceId.
| Name | Required | Description | Default |
|---|---|---|---|
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with tokenType (api_token or oauth), tokenId, tokenName, workspace { id }, organizationId, role { key, name }, issuerRole, permissions, can { draft, schedule, publish }, summary and expiresAt (null for a key that never expires). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false, and openWorldHint=false, so the safety profile is covered. The description adds real context beyond that: it discloses what information is returned, and the non-obvious constraint that an API key never holds more than its issuerRole.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The content is dense but front-loaded with the resource being described, and each clause earns its place. The single long sentence is slightly hard to parse but not padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present and annotations covering safety, the description needs only to convey purpose, usage timing, and key behavioral constraints — all of which it does, including the pre-emptive-check guidance and the issuerRole caveat.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the description's 'Takes only the optional workspaceId' plus 'the current one unless workspaceId names another' largely restates the schema's default-behavior documentation. Baseline 3 is appropriate since the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb (describe) and resource (this connection in the workspace) and enumerates exactly what is returned: auth type, role, permission keys, draft/schedule/publish capabilities, and a summary. This clearly distinguishes it from workspace-oriented siblings like list_workspaces or account tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use guidance: 'Call this before an action the role may not allow, instead of trying and reading a 403.' That names the alternative behavior it replaces, though it does not explicitly point to sibling tools for workspace discovery or role management.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_platform_breakdownGet Platform BreakdownARead-onlyInspect
The overview metrics split per platform for a date window, for "which platform performs best" comparisons. Returns { platforms }: one row per platform with analytics data, carrying followers, views, likes, comments, shares, postsCount, avgViewsPerPost and engagementRate (each { value, previousValue, deltaPercent }) plus supportedMetrics, the metrics that platform actually reports; compare only metrics both platforms list there. Google Business Profile reports location impressions only. Takes no platform filter; connectionIds narrows it to some accounts. Use get_analytics_overview for the combined total.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | End of the reporting window (ISO 8601). Must not be earlier than from | |
| from | Yes | Start of the reporting window as an ISO 8601 date or instant (e.g. "2026-08-01"). Metrics cover posts published between from and to; the comparison window is the same length immediately before from | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another | |
| connectionIds | No | Restrict to these accounts, by the account id from list_accounts; omit for every account |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with platforms: one { platform, followers, views, likes, comments, shares, postsCount, avgViewsPerPost, engagementRate, supportedMetrics } per platform. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered; the description adds genuinely non-obvious behavior beyond that — the absence of a platform filter, per-platform metric support via supportedMetrics, the instruction to compare only metrics both platforms list, and the Google Business Profile exception. Slight deduction because a chunk of the text restates return shape that the output schema already provides.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and use case, with the sibling routing at the end. The middle enumerates the return payload in detail, which duplicates the output schema and costs a little density, but nothing is misleading or padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only analytics aggregation with an output schema, full parameter documentation, and annotations, the description covers everything an agent needs: scope, selection criteria, the alternative tool, the platform-metric compatibility caveat, and the Google Business Profile edge case.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3 and the schema carries from/to/workspaceId/connectionIds semantics. The description still adds value the schema cannot express by explicitly stating that no platform-filter parameter exists and that connectionIds is the only narrowing mechanism.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource+scope: 'overview metrics split per platform for a date window.' It also names the contrasting sibling get_analytics_overview for the combined total, so the agent can distinguish it without reading a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the selecting use case ('which platform performs best' comparisons) and an explicit alternative with its condition ('Use get_analytics_overview for the combined total'). It also states a limitation the agent would otherwise probe for: 'Takes no platform filter; connectionIds narrows it to some accounts.'
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_postGet PostARead-onlyInspect
Get one post's full record by id: text, contentType, status, scheduledAt, timezone, and a platforms array with each target's connection, status, errorMessage, and media. Visible only within the workspace (the current one unless workspaceId names another); any other id returns "Post not found or access denied". Use this to inspect content before update_post or publish_draft. Use list_post_results instead when you only need per-platform publishing outcomes and the platformIds for retry_failed_platforms, and list_posts to find ids by status, platform, or date. Post ids come from create_post, bulk_schedule_posts, or list_posts.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Post ID from create_post, bulk_schedule_posts, or list_posts | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | The full post record: id, status, contentType, text, scheduledAt, timezone, mediaUrls, createdAt, updatedAt, recurringPostId and occurrenceAt (set when the post is an occurrence of a recurring post; occurrenceAt is its slot in the series and stays the same when the post is rescheduled), and platforms (one entry per target with id, platform, connectionId or pageId, status, errorMessage, platformPostId, postUrl once published, mediaUrls, previewUrls, and the per-platform settings: firstComment with firstCommentStatus PENDING, PUBLISHED or FAILED, firstCommentError and firstCommentPublishedAt; threadReplies with threadStatus, threadReplyIds, threadError and threadPublishedAt; thumbnailUrl and thumbnailTimestampMs overrides; mediaAspectRatio and mediaAspectRatioFit; instagramCollaborators, instagramUserTags, instagramUntaggedUsernames (tags Instagram refused), instagramAiGenerated, instagramUsername and instagramAudioId, instagramAudioTitle, instagramAudioArtist, instagramAudioVolume, instagramVideoVolume; facebookTextFormatPresetId, facebookImageLayout and facebookCarouselCards; youtubeAiGenerated; linkedinDocumentTitle and linkedinReshareOf; twitterKeepLinks; tumblrTags, tumblrTitle and tumblrSourceUrl; googleBusinessTopicType, googleBusinessCallToActionType, googleBusinessCallToActionUrl, googleBusinessEventTitle, googleBusinessEventStart, googleBusinessEventEnd and googleBusinessOffer fields). postUrl links to the published post on every platform; Instagram and Facebook stories expire after 24 hours, so for them it links to the profile or page. A shareToStory story is its own entry with postType STORY. previewUrls holds one permanent preview image per media item, a still frame for videos; after publishing, mediaUrls may become platform CDN links that expire within days, so show previewUrls instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, non-destructive, closed-world), but the description adds real behavioral context the annotations don't: visibility is scoped to the current or named workspace and out-of-scope ids return 'Post not found or access denied'. That error semantics is genuinely useful for interpreting failures, though nothing is said about payload size or performance limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and returned fields, then routing guidance; every clause is doing work. Slightly heavy for one paragraph, with some overlap between the field enumeration and the schema's id/workspaceId text, but no filler sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter read tool with an output schema and full annotation coverage, this is close to complete: what it returns, scope, error behavior, and sibling routing are all covered. The field-by-field enumeration is somewhat redundant given the output schema exists, but it does not leave gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters are already well documented in the schema, including the workspaceId consistency caveat. The description restates the id provenance ('from create_post, bulk_schedule_posts, or list_posts') and workspace scoping, adding little beyond what the structured fields already say.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get one post's full record by id') and immediately enumerates the fields returned, so the agent knows exactly what this retrieves. It is clearly differentiable from list_posts (find ids) and list_post_results (per-platform outcomes).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use ('inspect content before update_post or publish_draft') and names two alternatives with the precise conditions that select them (list_post_results for per-platform outcomes and platformIds for retry_failed_platforms; list_posts for finding ids by status/platform/date). It also names the upstream tools that produce valid ids.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_recurring_postGet Recurring PostARead-onlyInspect
Get one recurring post (series) by id: status, pauseReason and lastError when paused, the schedule (frequency, interval, weekdays, startsAt, timezone, endsOn, maxOccurrences), nextOccurrenceAt (the next slot not yet created as a post; absent once ENDED), occurrenceCount (posts created so far), and the content and platforms each occurrence copies. Ids outside the workspace (the current one unless workspaceId names another) return "Recurring post not found". Ids come from list_recurring_posts, the recurringPostId returned by create_post, or the recurringPostId on a post from get_post or list_posts.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Recurring post ID from list_recurring_posts, create_post, or a post's recurringPostId | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | The recurring post: id, userId, status, pauseReason, lastError, frequency, interval, weekdays, startsAt, timezone, endsOn, maxOccurrences, nextOccurrenceAt, occurrenceCount, contentType, text, mediaUrls, mediaAltTexts, thumbnailUrl, platformTypes, platforms, createdAt, and updatedAt. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/non-destructive, so the safety bar is low; the description goes further by disclosing the exact fields returned, the semantic of nextOccurrenceAt (next slot not yet created; absent once ENDED), and the cross-workspace error message. It stops short of describing pagination or auth requirements, but for a read tool that is minor.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One dense but front-loaded sentence that leads with the verb/resource and then enumerates returned data. The field list is long, but each item is meaningful; nothing is padded with filler or restated boilerplate.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description needn't re-explain return values, yet it adds the semantics an agent needs (nextOccurrenceAt absence at ENDED, cross-workspace not-found behavior, id provenance). Nothing required to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both id and workspaceId are already documented in the schema, giving a baseline of 3. The description reinforces id sourcing and workspace scoping but adds no syntax or format detail beyond what the schema already carries.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Get) and resource (one recurring post/series) by id, and immediately differentiates from list_recurring_posts by scoping to a single record. An agent can tell it apart from the sibling list tool without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells the agent where valid ids come from (list_recurring_posts, create_post's recurringPostId, get_post/list_posts), which is the key prerequisite for calling it. It gives clear context but never states a when-not-to-use case or explicitly contrasts with list_recurring_posts.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_rss_feedGet RSS FeedARead-onlyInspect
Get one RSS feed by id: its settings, targets, status, pauseReason and lastError, and when it was last checked and last posted. Use list_rss_feed_items to see what it did with each item. Ids outside the workspace return 404. Needs the posts.read permission.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | RSS feed id from list_rss_feeds or create_rss_feed | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | The RSS feed: id, userId (the member it posts as, whoever last saved it), name, url, siteUrl, status (ACTIVE or PAUSED), pauseReason, lastError, postMode, publishDelayMinutes, contentMode, template, aiInstructions, includeImage, twitterKeepLinks, includeKeywords, excludeKeywords, maxPostsPerCheck, checkIntervalMinutes, targets, nextCheckAt, lastCheckedAt, lastPostedAt, createdAt and updatedAt. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this a safe, non-destructive read, so the bar is lower; the description still adds real behavioral context the annotations lack—the required posts.read permission and a 404 for out-of-workspace ids. That cross-workspace failure mode is exactly the kind of detail an agent needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the resource and payload contents, then adds only two short, high-value sentences on sibling scope and permissions. Every sentence earns its place; slightly list-like phrasing keeps it just below exemplary.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the field enumeration in the description is a bonus rather than a requirement. Auth requirement and error behavior are covered; cross-workspace scoping is handled by the schema's workspaceId text, so little is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, including detailed workspaceId semantics, so the schema carries the parameter burden. The description only repeats that lookup is by id and does not add format or sourcing detail beyond what the schema already says.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get one RSS feed by id') and enumerates exactly what it returns: settings, targets, status, pauseReason, lastError, last checked/posted timestamps. This clearly distinguishes it from list_rss_feeds and list_rss_feed_items without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes item-level inspection to list_rss_feed_items, which is the most likely alternative an agent would confuse it with. It does not explicitly contrast with list_rss_feeds or check_rss_feed, so the guidance is clear but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_upload_ticketGet Upload TicketAInspect
Called by the upload box that open_upload_widget shows, once per file, to authorize storing that file in AdaptlyPost media storage. Returns a ticket valid for 5 minutes. Do not call this yourself; call open_upload_widget instead.
| Name | Required | Description | Default |
|---|---|---|---|
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with expiresAt and uploadUrl for the upload box. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnlyHint=false, destructiveHint=false, and openWorldHint=false. The description adds non-obvious behavior the annotations cannot express: the ticket has a 5-minute validity window and is issued per-file. It does not describe failure modes or auth requirements, keeping it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences: purpose, return/validity, and the routing exclusion. Front-loaded and every sentence carries distinct information with no repetition of the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation. Combined with full schema coverage on the only parameter and explicit routing, an agent has everything needed to call it correctly or defer to open_upload_widget.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for the single workspaceId parameter, with rich guidance about defaults and cross-workspace id semantics, so the description correctly defers. It adds no parameter detail beyond the schema, which is the baseline-3 case.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (authorize storing a file, returning an upload ticket) and ties it to a named sibling mechanism (the upload box shown by open_upload_widget). An agent can distinguish it from get_upload_urls and upload_media without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when-not: 'Do not call this yourself; call open_upload_widget instead.' It also specifies the call cadence ('once per file'), removing ambiguity about batching or looping.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_upload_urlsGet Media Upload URLsAInspect
Get presigned upload URLs for direct file uploads. Returns uploadUrl (PUT your file here) and publicUrl (use in create_post mediaUrls). This only mints a URL. You MUST PUT the file to uploadUrl and confirm a 2xx response before using publicUrl, otherwise create_post/bulk rejects it with "Media file(s) not found in storage". If the PUT cannot reach uploadUrl, for example a sandbox network proxy answers 403 or the storage host is not on its allowlist, do not retry it and do not stop: hand the files to the user as downloads, call open_upload_widget, and ask the user to add them in the upload box, which returns the mediaUrls. Prefer upload_media for public URLs and for inline files under 30 MB; use this for larger files you hold yourself. For each file, provide fileName and mimeType. Supported types: image/jpeg, image/png, image/webp, image/gif (Facebook, X, Bluesky, Mastodon, LinkedIn and Tumblr only), video/mp4, video/quicktime, and for LinkedIn DOCUMENT posts application/pdf, application/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation, application/msword and application/vnd.openxmlformats-officedocument.wordprocessingml.document; keep the extension in fileName, since the post reads the file type from it. A publicUrl may be reused across any number of posts; the file is kept until the last post referencing it has published.
| Name | Required | Description | Default |
|---|---|---|---|
| files | Yes | Files to get upload URLs for | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with urls: one { uploadUrl, publicUrl, key } entry per requested file. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes far beyond the annotations by disclosing the two-step mint-then-PUT workflow, the exact failure mode ('Media file(s) not found in storage'), proxy/allowlist 403 behavior, the no-retry fallback, publicUrl reuse semantics, and retention until the last referencing post publishes. The annotations already mark this as a non-destructive, closed-world operation; the description adds the operational context an agent needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, return values, and the mandatory PUT confirmation, then moves to fallback and sibling preference. It is dense and largely earns its length given the workflow complexity, though the long sandbox-proxy sentence and the redundant 'provide fileName and mimeType' line could be tightened.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, return semantics (uploadUrl vs publicUrl), mandatory confirmation, failure recovery, alternatives, supported types with platform caveats, and URL reuse lifetime. With an output schema present and 100% schema coverage, nothing material is missing for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds real meaning: the fileName extension matters because the post reads file type from it, and the supported MIME types carry platform-specific restrictions (GIF only on certain networks, PDF/Office documents only for LinkedIn DOCUMENT posts) not present in the enum. It does not mention the 20-file cap or workspaceId, but both are well documented in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb and resource: 'Get presigned upload URLs for direct file uploads,' and immediately clarifies that it only mints a URL rather than performing the upload. This cleanly distinguishes it from upload_media and open_upload_widget.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes between siblings: prefer upload_media for public URLs and inline files under 30 MB; use this for larger self-held files; fall back to open_upload_widget when the PUT cannot reach storage. It also states the mandatory 2xx confirmation before create_post/bulk will accept the publicUrl.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_webhookGet WebhookARead-onlyInspect
Get one webhook endpoint by id. Ids outside the workspace return 404. Needs the webhooks.read permission.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Webhook id from list_webhooks or create_webhook | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | The webhook: id, url, active, createdAt, updatedAt, lastSuccessAt, lastFailureAt and disabledAt (set when it was turned off after 20 failed deliveries in a row). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds useful behavioral context beyond that: cross-workspace ids return 404 and the caller needs the webhooks.read permission.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the core operation, followed by the two most relevant constraints (404 behavior and required permission). No sentence is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so the description need not explain return values, and annotations cover the safety profile. The description supplies the key scoping and auth constraints, leaving it largely complete for a simple read-by-id tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and both the id and workspaceId parameters are documented richly in the schema itself. The description adds no additional parameter meaning beyond what the schema already provides, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ('Get one webhook endpoint by id') and clearly scopes the operation to a single resource, distinguishing it implicitly from list_webhooks. It does not explicitly name the sibling tools it differs from, so it falls short of the top score.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'by id' implies this is the tool to use when an id is already known, but it never states when to prefer this over list_webhooks or how to obtain an id beyond the schema note. Usage is implied rather than explicitly guided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_accountsList Connected AccountsARead-onlyInspect
List the social accounts connected to the workspace (the current one unless workspaceId names another) across all thirteen platforms. Returns { accounts } with id, platform, displayName, username, avatarUrl, status, pageId for Facebook pages, and supportsInstagramAudio for Instagram (true when the account can add audio to Reels, see search_instagram_audio). For a Pinterest account, list_pinterest_boards returns the boards it can pin to. For a Google Business Profile location displayName is the location title and username is empty; its id goes in googleBusinessConnectionIds. status is active or unauthorized; an unauthorized account (unauthorizedReason carries the platform's message) is refused with 400 by create_post until the user reconnects it in AdaptlyPost, so leave it out and tell the user. Call this before create_post, update_post, or bulk_schedule_posts: they take these ids, never usernames. Pass the ids as accountIds, or put each id in the array for its platform (linkedinConnectionIds, tumblrConnectionIds, telegramConnectionIds, and so on); Facebook page accounts go in pageIds. check_account re-checks a Facebook page with Facebook, and remove_account disconnects an account. Not for post history or publishing status: use list_posts or list_post_results for those. Takes only the optional workspaceId.
| Name | Required | Description | Default |
|---|---|---|---|
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with accounts: one { id, platform, displayName, username, avatarUrl, status } per connected account, plus unauthorizedReason when status is unauthorized, pageId for Facebook pages and supportsInstagramAudio for Instagram. Use id as the connection id (or in pageIds for Facebook). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly annotation, the description discloses critical behavior: unauthorized accounts cause 400 errors in create_post until reconnection, should be excluded, and the user notified. It also covers platform-specific quirks such as Facebook page IDs, Google Business Profile displayName/username, and Instagram audio support.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense and front-loads the core purpose, but it is a long single paragraph mixing return fields, platform-specific caveats, and related tools. Most sentences earn their place, though a more structured format would improve scanability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a simple list operation with one optional parameter and an output schema, the description is complete: it covers return fields, platform-specific behaviors, error conditions, and routing to alternatives. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one optional parameter exists and schema coverage is 100%. The description notes 'Takes only the optional workspaceId' and clarifies the current-workspace default, but the schema already documents the workspaceId semantics in detail, so the description adds limited extra meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'List the social accounts connected to the workspace... across all thirteen platforms.' It clearly distinguishes this tool from post-listing tools and names the scope precisely.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states when to call it ('before create_post, update_post, or bulk_schedule_posts'), alternatives for related needs ('check_account', 'remove_account'), and exclusions ('Not for post history or publishing status: use list_posts or list_post_results'). This leaves little ambiguity for an agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_discovered_postsList Discovered PostsARead-onlyInspect
Posts found on the connected accounts that were not published through AdaptlyPost (published natively or with another tool), inside the window: text, thumbnail, permalink, account and publish time. They are read-only; their metrics are in list_post_analytics. Use it to show what an account posted outside AdaptlyPost or to fill in the calendar. Needs the analytics.read permission.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | End of the reporting window (ISO 8601). Must not be earlier than from | |
| from | Yes | Start of the reporting window as an ISO 8601 date or instant (e.g. "2026-08-01"). Metrics cover posts published between from and to; the comparison window is the same length immediately before from | |
| limit | No | Posts to return, 1 to 1000 (default 200) | |
| platforms | No | Restrict to these platforms; omit for every platform with analytics. MASTODON, TELEGRAM and TUMBLR have no analytics and are ignored. GOOGLE_BUSINESS reports location impressions only, with no per-post numbers | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another | |
| connectionIds | No | Restrict to these accounts, by the account id from list_accounts; omit for every account |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with posts: one { id, platform, publishedAt, text, thumbnailUrl, permalink, connectionId, accountName } per post. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and destructiveHint=false, so the safety profile is covered; the description still adds value by stating 'they are read-only', naming the required analytics.read permission, and noting that metrics live in another tool. It does not cover pagination/volume behavior beyond what the schema provides.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Content is front-loaded with the defining scope in the first sentence and each subsequent sentence carries a distinct fact (read-only, metrics location, use cases, permission). Slightly dense but no filler sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return shape need not be described; the description covers scope, safety, permission requirement, and the sibling holding metrics. An agent has everything needed to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter (from, to, limit, platforms, workspaceId, connectionIds) is already documented in the schema. The description only restates the window concept ('inside the window') without adding format or semantics beyond the schema, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with a precise scope: posts on connected accounts NOT published through AdaptlyPost, with listed fields (text, thumbnail, permalink, account, publish time). This clearly distinguishes it from list_posts (published via the tool) and routes metric needs to list_post_analytics.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete use cases ('show what an account posted outside AdaptlyPost or to fill in the calendar') and names the sibling that holds the complementary data (list_post_analytics). It does not explicitly say when to prefer list_posts over this, but the scope statement makes the boundary inferable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_pinterest_boardsList Pinterest BoardsARead-onlyInspect
List the boards of a connected Pinterest account, secret boards included. Returns { boards } with id, name, description, privacy (PUBLIC, PROTECTED or SECRET) and pinCount. Call it before posting to Pinterest, ask the user which board to pin to unless they already named one, and pass that board's id as pinterestConfigs[].boardId in create_post, update_post or bulk_schedule_posts. When the user named a board you may pass that name as boardName instead, never both; a name that matches no board, or several, fails with 400 and nothing falls back. A board belongs to one Pinterest account, so call it once per Pinterest account. A post sent without boardId or boardName goes to a public board named AdaptlyPost, which is created on first use. Fails with 404 when accountId is not a Pinterest account in the workspace, and with 400 when Pinterest refuses the request, which usually means the user must reconnect the account in AdaptlyPost. Nothing is posted.
| Name | Required | Description | Default |
|---|---|---|---|
| accountId | Yes | The Pinterest account id from list_accounts | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with boards: one { id, name, description, privacy, pinCount } per board. Pass id as pinterestConfigs[].boardId, or name as boardName. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, but the description goes further by disclosing the failure modes that matter operationally: 404 when accountId is not a Pinterest account, 400 when Pinterest refuses (usually a reconnect), and 400 on ambiguous/unmatched board names. It explicitly states the default-board behavior for posts that omit a board, which is a hidden side effect an agent would otherwise discover only by accident.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and return shape, then usage, then errors — a sensible ordering with no filler sentences. It is on the long side for a two-parameter read tool, and a couple of clauses describe downstream posting behavior (the AdaptlyPost default) that more properly belongs to create_post, though they are relevant for interpreting this tool's output.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description need not enumerate return values, yet it summarizes them anyway. Combined with the error semantics, the cross-account scoping rule, and the explicit 'Nothing is posted' reassurance, an agent has everything needed to call this correctly and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description still adds meaning by clarifying that accountId maps to a Pinterest account from list_accounts, that a board belongs to exactly one account ('call it once per Pinterest account'), and that boardId/boardName are downstream-only fields. It does not add syntax detail for either parameter beyond the schema, hence not a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the boards of a connected Pinterest account') and immediately scopes it ('secret boards included'), which distinguishes it from sibling list_accounts and list_posts. The return shape is named up front, so an agent knows exactly what it gets.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use ('call it before posting to Pinterest'), the user-interaction step (ask which board unless already named), and the exact target of the result (pinterestConfigs[].boardId in create_post, update_post, bulk_schedule_posts). It also rules out the mutually exclusive alternative: boardName instead, 'never both', and confirms there is no fallback on ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_post_analyticsList Post AnalyticsARead-onlyInspect
Per-post metrics for posts published inside the window, sorted by a metric or by publish date, paginated. Use it for "top posts", "which post got the most comments" and "how did post X do". Covers posts published through AdaptlyPost and posts discovered on the connected accounts; Google Business Profile posts are listed with null metrics, since that platform reports only location impressions; discovered posts have postId and postPlatformId set to null, while AdaptlyPost posts carry the postId used by get_post. Returns { posts, total, page, limit, hasMore }; each post has platform, publishedAt, title, thumbnailUrl, permalink, connectionId, accountName and metrics { views, likes, comments, shares, saves, clicks, impressions, reach, engagementRate, plus engagedViews, averageViewDurationSeconds and averageViewPercentage on YouTube }, with null for metrics the platform does not report. Sort by a metric for a ranked list (list_top_posts returns the top few in one call); PUBLISHED_AT (default) for a chronological review. Not for publishing status: use list_post_results for that.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | End of the reporting window (ISO 8601). Must not be earlier than from | |
| from | Yes | Start of the reporting window as an ISO 8601 date or instant (e.g. "2026-08-01"). Metrics cover posts published between from and to; the comparison window is the same length immediately before from | |
| page | No | Page number, from 1 | |
| limit | No | Posts per page, 1 to 100 | |
| sortBy | No | Metric to sort by, descending. PUBLISHED_AT (default) lists newest first | |
| platforms | No | Restrict to these platforms; omit for every platform with analytics. MASTODON, TELEGRAM and TUMBLR have no analytics and are ignored. GOOGLE_BUSINESS reports location impressions only, with no per-post numbers | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another | |
| connectionIds | No | Restrict to these accounts, by the account id from list_accounts; omit for every account |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with posts (each { id, postId, postPlatformId, platform, publishedAt, title, thumbnailUrl, permalink, connectionId, accountName, metrics }), total, page, limit, and hasMore. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/non-destructive annotations, it discloses source coverage (AdaptlyPost vs discovered posts vs Google Business Profile) and the consequence: GBP posts appear with null metrics, discovered posts have null postId/postPlatformId, and unreported metrics are null. This is exactly the kind of edge-case behavior an agent cannot infer from annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and use cases, and every sentence carries information. It is dense, however, and the long return-shape enumeration partially duplicates the existing output schema, adding length without new decision-relevant content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a read tool with 8 parameters, null-heavy edge cases, and a sibling-heavy family. The description covers platform quirks, ID nullability, sorting intent, and cross-tool routing, leaving nothing an agent needs in order to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema carries parameter definitions and the baseline is 3. The description still adds interpretive value by explaining the sorting strategy (sort by a metric for a ranked list, PUBLISHED_AT default for chronological review), which tells the agent how to choose sortBy rather than just what it accepts.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ('Per-post metrics for posts published inside the window') and immediately scopes behavior: sort options and pagination. It explicitly separates itself from siblings by naming list_top_posts, list_post_results, and get_post, so an agent can pick correctly without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete triggering questions ('top posts', 'which post got the most comments', 'how did post X do'), names the alternative (list_top_posts returns the top few in one call), and states an exclusion ('Not for publishing status: use list_post_results'). The when/when-not/alternative triad is fully covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_post_resultsList Post ResultsARead-onlyInspect
Get one post's per-platform publishing outcomes: { postId, status, results[] } where each result has platformId, platform, accountName, status (PENDING, PUBLISHING, PUBLISHED, or FAILED), platformPostId, errorMessage, publishedAt, and tiktokDraftFallback (true when TikTok's daily cap sent the content to the TikTok inbox as a draft instead of publishing it; tell the user to finish it in the TikTok app). Each platform reports separately, so read every row instead of treating the post as one pass or fail. Call this after create_post, publish_draft, or retry_failed_platforms, since publishing is asynchronous and their responses only confirm queueing; poll until no row is PENDING or PUBLISHING. Take platformId from FAILED rows for retry_failed_platforms. Use get_post when you also need the content and schedule.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Post ID from create_post, publish_draft, bulk_schedule_posts, or list_posts | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with postId, the overall post status, and results: one { platformId, platform, accountName, status, platformPostId, errorMessage, tiktokDraftFallback, publishedAt } per targeted platform. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safe-read profile, and the description adds substantial context beyond them: the asynchronous/polling behavior, the requirement to read every platform row rather than treat the post as one pass/fail, and the tiktokDraftFallback semantics with an actionable directive to tell the user to finish the draft in the TikTok app.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the return shape and dense with actionable content; every sentence carries a directive. It is somewhat long and the tiktokDraftFallback sentence is heavily packed, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an asynchronous, per-platform results tool, the description covers the polling loop, row-level reading, failure handoff to retry_failed_platforms, and the special TikTok fallback. Even though an output schema exists, the behavioral guidance is complete for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents both 'id' and 'workspaceId'. The description adds no syntax or format detail beyond what the schema provides, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get one post's per-platform publishing outcomes') and immediately names the sibling it is not ('Use get_post when you also need the content and schedule'). An agent can distinguish it from get_post and list_posts without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to call it ('after create_post, publish_draft, or retry_failed_platforms'), why ('publishing is asynchronous and their responses only confirm queueing'), and the exact completion condition ('poll until no row is PENDING or PUBLISHING'). It also routes platformId extraction to retry_failed_platforms and points to get_post for the alternative need.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_postsList PostsARead-onlyInspect
List posts in the workspace (the current one unless workspaceId names another), any status, newest first by default. Returns { posts, total, hasMore }; each post carries its status and a platforms array with per-platform status. Filters: statuses, platforms (posts targeting any of them), and startDate/endDate, which bound scheduledAt, or createdAt for posts never scheduled. limit is 1 to 100 (default 20); page with offset while hasMore is true. Use this to find post ids or check what is already queued. Use get_post for one post's full record and list_post_results for one post's per-platform outcomes and retry ids.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results, 1 to 100 | |
| offset | No | Posts to skip; increase by limit while hasMore is true | |
| endDate | No | Upper bound (ISO 8601, e.g. "2026-03-31") on scheduledAt, or createdAt for posts never scheduled | |
| statuses | No | Filter by status (e.g. ["SCHEDULED", "DRAFT"]); omit for all statuses | |
| platforms | No | Filter to posts targeting any of these platforms | |
| sortOrder | No | NEWEST (default) or OLDEST | |
| startDate | No | Lower bound (ISO 8601, e.g. "2026-03-01") on scheduledAt, or createdAt for posts never scheduled | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with posts (each with id, status, contentType, text, scheduledAt, timezone, recurringPostId and occurrenceAt for occurrences of a recurring post, and platforms with per-platform status), total (count of all matches), and hasMore. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/openWorld=false/destructive=false, and the description adds substantive context beyond them: default newest-first ordering, the aggregate return shape { posts, total, hasMore }, that each post carries status plus a per-platform platforms array, and that startDate/endDate bound scheduledAt or createdAt for unscheduled posts. Pagination contract (offset while hasMore) is spelled out.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and scope, then return shape, then filters, then routing to siblings. No sentence is redundant despite covering a lot of ground.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter, zero-required listing tool with an output schema, the description covers scope, ordering, filtering semantics, pagination, and sibling routing. Nothing an agent needs in order to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description still earns credit by explaining that platforms matches posts targeting ANY of the listed platforms and by restating the date-bound semantics and the 1-100/20 default. It adds meaning rather than merely echoing the schema, though most of the syntax detail already lives in the fields.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (list posts), defines scope (current workspace unless workspaceId names another), default ordering, and return shape. It also explicitly distinguishes itself from get_post and list_post_results, so an agent can choose without opening another schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the positive use case ('find post ids or check what is already queued') and names the two alternatives with the conditions that select them: get_post for a full record, list_post_results for per-platform outcomes and retry ids.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_recurring_postsList Recurring PostsARead-onlyInspect
List the recurring posts (series) in the workspace (the current one unless workspaceId names another), created by passing recurrence to create_post. Returns { recurringPosts, total, hasMore }; each series has id, status (ACTIVE, PAUSED or ENDED), pauseReason when paused, frequency, interval, weekdays, startsAt, timezone, endsOn or maxOccurrences, nextOccurrenceAt, occurrenceCount, and the content and platforms every occurrence copies. Only the next occurrence of an ACTIVE series exists as a SCHEDULED post, created about 24 hours ahead; list_posts shows it with recurringPostId set. A series pauses itself after 3 failed posts in a row, when the subscription lapses, when its creator loses workspace access, when one of its accounts is disconnected, or when a platform rejects the content; pauseReason and lastError say which. limit is 1 to 100 (default 20); page with offset while hasMore is true. Editing a series or skipping one date is only possible in the AdaptlyPost app.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results, 1 to 100 | |
| offset | No | Recurring posts to skip; increase by limit while hasMore is true | |
| statuses | No | Filter by status (e.g. ["ACTIVE", "PAUSED"]); omit for all statuses | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with recurringPosts (each with id, status, pauseReason, lastError, frequency, interval, weekdays, startsAt, timezone, endsOn, maxOccurrences, nextOccurrenceAt, occurrenceCount, contentType, text, mediaUrls, platformTypes, and platforms), total (count of all matches), and hasMore. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the read-only, non-destructive, closed-world profile, and the description adds substantial non-obvious behavior: only the next occurrence of an ACTIVE series exists as a SCHEDULED post (~24 hours ahead), and the five conditions that self-pause a series (3 consecutive failures, lapsed subscription, creator losing access, disconnected account, platform rejection) with pauseReason/lastError as the signal. That is exactly the kind of lifecycle context annotations cannot provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and return shape, then lifecycle and pagination detail. It is dense but nearly every sentence carries information; the one partial redundancy is restating the limit range and default that the schema already specifies.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only list tool with a full output schema, the description covers purpose, filtering, pagination, workspace scoping, and the lifecycle semantics an agent needs to interpret statuses and pause reasons. Nothing material for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so limit, offset, statuses, and workspaceId are already documented in structured form. The description largely restates these (limit 1-100 default 20, paging with offset), adding little beyond the schema, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the recurring posts (series) in the workspace') and immediately defines what a recurring post is (created by passing recurrence to create_post). This lets an agent distinguish it from get_recurring_post, list_posts, and delete_recurring_post without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear usage context: pagination via offset/limit while hasMore is true, workspaceId should be reused for related calls, and it points out that list_posts surfaces the scheduled next occurrence. It does not explicitly state when to prefer this over get_recurring_post (single series) or how it relates to the pause/resume siblings, so routing guidance is slightly incomplete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_rss_feed_itemsList RSS Feed ItemsARead-onlyInspect
List the items an RSS feed has seen, newest first, leaving out the ones already in the feed when it was added. Each item has a status: PROCESSING, POSTED (postId links it to its post, for get_post), FILTERED (keyword rules), SKIPPED (published more than 14 days before the feed was added) or FAILED (error says why). Use it to answer why an article was or was not posted. Needs the posts.read permission.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | RSS feed id from list_rss_feeds or create_rss_feed | |
| limit | No | Max items, 1 to 100 (default 20) | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with items: one { id, createdAt, title, link, publishedAt, status, postId, error } per item. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare a safe read, and the description adds substantial context beyond them: ordering, the exclusion rule for pre-existing items, the five-value status taxonomy with what each means, the 14-day skip threshold, and the required posts.read permission. That is exactly the behavioral detail an agent needs before calling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three compact sentences, front-loaded with the core behavior, then the status semantics, then the use case and permission. Every clause carries information; nothing is padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and the description covers what matters for interpretation: status meanings, the postId link to get_post, and the auth requirement. Nothing an agent needs to call or interpret this tool is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, with id, limit, and workspaceId all documented including defaults and cross-workspace id cautions. The description adds no further parameter detail (e.g., what happens at limit boundaries or pagination), so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the items an RSS feed has seen') plus scope details: newest-first ordering and exclusion of items that predate the feed's creation. This clearly separates it from list_rss_feeds (lists feeds) and preview_rss_feed (tests ingestion).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Use it to answer why an article was or was not posted' gives a concrete selection scenario tied to the status field. It does not explicitly name alternatives such as preview_rss_feed or check_rss_feed, so it stops short of full when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_rss_feedsList RSS FeedsARead-onlyInspect
List the RSS and Atom feeds connected to the workspace (the current one unless workspaceId names another), newest first; a workspace holds at most 20. Each new item of a feed becomes a post on its targets. A feed pauses itself after 5 failed fetches in a row (FETCH_FAILURES), 3 items in a row that failed to post (CONSECUTIVE_FAILURES), when its owner loses the permission its post mode needs (ACCESS_LOST), when the plan no longer covers publishing (SUBSCRIPTION_INACTIVE) or when every target account was disconnected (CONNECTION_REMOVED); pauseReason and lastError say which. Needs the posts.read permission. Takes only the optional workspaceId.
| Name | Required | Description | Default |
|---|---|---|---|
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with rssFeeds: one record per feed. The RSS feed: id, userId (the member it posts as, whoever last saved it), name, url, siteUrl, status (ACTIVE or PAUSED), pauseReason, lastError, postMode, publishDelayMinutes, contentMode, template, aiInstructions, includeImage, twitterKeepLinks, includeKeywords, excludeKeywords, maxPostsPerCheck, checkIntervalMinutes, targets, nextCheckAt, lastCheckedAt, lastPostedAt, createdAt and updatedAt. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/non-destructive/closed-world, so the bar is lower, yet the description still adds substantial context: the 20-feed cap, the feed-to-post relationship, the posts.read permission requirement, and the full set of pause states (FETCH_FAILURES, CONSECUTIVE_FAILURES, ACCESS_LOST, SUBSCRIPTION_INACTIVE, CONNECTION_REMOVED) with the note that pauseReason and lastError identify which. That is genuine behavioral disclosure an agent could not get from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and scope are front-loaded in the first clause, and every sentence is information-dense. The pause-state enumeration is long for a listing tool and arguably belongs with the feed resource, but it earns its place by explaining pauseReason values.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values needn't be described, and the description still covers scope, ordering, limits, permissions, and the meaning of the pause fields. Nothing an agent needs in order to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single optional workspaceId already documents the default-workspace behavior and cross-workspace id caveat, so the parameter is fully specified without the description. The description's 'the current one unless workspaceId names another' restates the schema rather than adding new semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the RSS and Atom feeds'), scopes it to the workspace, and adds ordering ('newest first') and a hard cap ('at most 20'). This clearly separates it from get_rss_feed and list_rss_feed_items, which operate on a single feed or its items.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the listing verb and the note that it takes only the optional workspaceId, so an agent can infer this is the enumeration call. However, no sibling is named (get_rss_feed, check_rss_feed, preview_rss_feed, list_rss_feed_items) and there is no explicit when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_top_postsList Top PostsARead-onlyInspect
The best-performing posts published inside the window, ranked by one metric (VIEWS by default), in one call: the same rows as list_post_analytics without pagination. Use it for "what were our top 5 posts this month". Covers posts published through AdaptlyPost and posts discovered on the connected accounts (postId null). connectionIds narrows it to some accounts. Needs the analytics.read permission.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | End of the reporting window (ISO 8601). Must not be earlier than from | |
| from | Yes | Start of the reporting window as an ISO 8601 date or instant (e.g. "2026-08-01"). Metrics cover posts published between from and to; the comparison window is the same length immediately before from | |
| limit | No | Posts to return, 1 to 50 (default 10) | |
| sortBy | No | Metric to rank by, descending (default VIEWS) | |
| platforms | No | Restrict to these platforms; omit for every platform with analytics. MASTODON, TELEGRAM and TUMBLR have no analytics and are ignored. GOOGLE_BUSINESS reports location impressions only, with no per-post numbers | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another | |
| connectionIds | No | Restrict to these accounts, by the account id from list_accounts; omit for every account |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with posts: one { id, postId, postPlatformId, platform, publishedAt, title, thumbnailUrl, permalink, connectionId, accountName, metrics } per post, best first. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so safety is covered by structured data. The description adds genuinely new behavioral context: the required analytics.read permission, that results include posts discovered on connected accounts with null postId, and that ranking is descending.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with what the tool returns and how it differs from the sibling, then packs coverage, scoping and permission notes into a compact paragraph. Slightly dense but no sentence is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be explained, and the description covers permissions, data coverage (AdaptlyPost vs. discovered posts), scoping via connectionIds, and the ranking default. Nearly complete for a 7-parameter read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so defaults, enums, limits and ISO formats are already fully documented in the schema. The description only restates connectionIds narrowing and the default VIEWS metric, which the schema already states, so it adds little beyond the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (top-performing posts ranked by one metric) and precisely distinguishes it from the sibling list_post_analytics by noting it returns 'the same rows ... without pagination'. An agent can pick the right tool without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete triggering example ('what were our top 5 posts this month') and names the alternative it shadows (list_post_analytics without pagination), so the selection is clear. It stops short of an explicit 'do not use when' condition, e.g. when you need the full paginated dataset.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_webhooksList WebhooksARead-onlyInspect
List the webhook endpoints registered for the workspace (the current one unless workspaceId names another), with whether each is active and when it last succeeded or failed. Needs the webhooks.read permission, which Admin, Editor and Viewer hold. Takes only the optional workspaceId.
| Name | Required | Description | Default |
|---|---|---|---|
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with webhooks: one record per endpoint. The webhook: id, url, active, createdAt, updatedAt, lastSuccessAt, lastFailureAt and disabledAt (set when it was turned off after 20 failed deliveries in a row). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false and openWorldHint=false, so safety is covered; the description adds real value beyond them by naming the required permission and roles and by stating what is returned (active flag, last success/failure). It says nothing about result volume or pagination, which is the remaining gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with what is listed, followed by the return content and then the permission/parameter facts. Every clause carries information an agent would otherwise have to infer.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description needn't detail return shapes, and annotations cover the safety profile. What remains — permission requirements, workspace defaulting, and which fields matter — is all stated, so an agent can call this correctly without further reading.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the workspaceId description already explains the id source and cross-workspace id hazard. The description still adds the useful default rule ("the current one unless workspaceId names another") and confirms it is the only, optional parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("List the webhook endpoints registered for the workspace") and even enumerates the returned fields (active status, last success/failure). The list-vs-single distinction against get_webhook is implicit rather than named, so it falls just short of explicit sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear operating context: it needs webhooks.read (held by Admin, Editor, Viewer) and takes only the optional workspaceId. It does not explicitly say when to prefer get_webhook or list_posts-style alternatives, but for a simple enumerator the applicable conditions are covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_workspacesList WorkspacesARead-onlyInspect
List the workspaces this sign-in can act in, across every organization the user belongs to. Returns { workspaces } with id, name, organization { id, name }, role { key, name }, permissions (the permission keys held there), isDefault, current and can { draft, schedule, publish }. Call this when the user names a workspace, brand, client or organization, or when accounts or posts they expect are missing: then pass the matching id as workspaceId to every other tool. Without workspaceId, tools act in the workspace marked current. An API key belongs to one workspace, so it lists only that one. Takes no arguments.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with workspaces: one { id, name, organization, role, permissions, isDefault, current, can } per workspace. Pass id as workspaceId to other tools. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/openWorld/destructive hints, and the description goes beyond them with real behavioral context: the API-key scoping rule ('an API key belongs to one workspace, so it lists only that one') and the default-current-workspace behavior that governs every other tool. It does not mention pagination or result limits, which is the only notable omission for a cross-org list.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose, then the return shape, then the usage condition and cross-tool wiring; every sentence carries operational value. The trailing 'Takes no arguments' is mildly redundant against the empty schema, a small blemish on an otherwise tight structure.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return-field documentation is not strictly required, yet the description still summarizes the payload. Combined with the workspaceId routing rule and API-key exception, an agent has everything needed to call this tool correctly and to use its results in subsequent calls.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so the baseline is 4 per the rubric. The description confirms 'Takes no arguments,' which is consistent with the empty schema but adds no semantic detail beyond it, as expected for a parameterless tool.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with scope: 'List the workspaces this sign-in can act in, across every organization the user belongs to.' It is immediately distinguishable from sibling list tools like list_accounts, and it even enumerates the returned fields so the agent knows the tool's identity without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit trigger conditions are given ('when the user names a workspace, brand, client or organization, or when accounts or posts they expect are missing') along with the follow-up action ('pass the matching id as workspaceId to every other tool'). It also states the fallback semantics when no workspaceId is supplied, so the agent knows when this tool is required versus optional.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
open_upload_widgetUpload From DeviceAInspect
Show an upload box in the chat so the user can add photos, videos or documents from their phone or computer. Use it when the user wants to post a file that has no public URL, such as a photo on their phone, a file attached in the chat that upload_media cannot read (in ChatGPT, pass attached files to upload_media as attachments instead), or a file you built in a sandbox whose network blocks the get_upload_urls uploadUrl. Nothing is uploaded until the user picks files in the box. When the upload finishes, the box sends a message listing the public media URLs; pass them as mediaUrls to create_post, update_post or bulk_schedule_posts. Accepts JPEG, PNG, WebP, GIF, MP4, QuickTime, PDF, PPT, PPTX, DOC and DOCX, up to 250 MB per file, 50 MB per image and 100 MB per document. Uploaded files are stored at public URLs. The box only appears in apps that show MCP Apps widgets, such as ChatGPT and Claude; elsewhere ask the user for a public URL and use upload_media.
| Name | Required | Description | Default |
|---|---|---|---|
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with status waiting_for_upload. The media URLs arrive later, in a message the upload box sends when the user finishes. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only assert readOnlyHint=false, destructiveHint=false and openWorldHint=false. The description adds real behavior the annotations can't: nothing is uploaded until the user picks files, the box returns a message listing public media URLs meant for create_post/update_post/bulk_schedule_posts, uploaded files land at public URLs, and the widget only renders in MCP Apps hosts.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is front-loaded with the purpose before the conditions, and the size and type limits are packed into a single compact sentence. It runs long, and the parenthetical about ChatGPT attachments plus the repeated 'no public URL' framing cost a little density, but nothing is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
It covers the host compatibility limit, the upload handoff, and the file-type and size limits (250 MB per file, 50 MB per image, 100 MB per document). Because an output schema exists, the description doesn't need to enumerate return fields, so nothing is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is one optional parameter (workspaceId) and schema description coverage is 100%, so the schema already explains the id source and the current-workspace default. The description says nothing extra about it, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a concrete verb and resource: 'Show an upload box in the chat so the user can add photos, videos or documents.' It immediately frames the resource as the missing-URL case, which separates it from upload_media and get_upload_urls by name. An agent can pick this tool without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states the trigger ('when the user wants to post a file that has no public URL'), the exclusions ('a file attached in the chat that upload_media cannot read ... in ChatGPT, pass attached files to upload_media as attachments instead'), and the fallback ('elsewhere ask the user for a public URL and use upload_media'). The alternative tools are named explicitly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pause_recurring_postPause Recurring PostADestructiveIdempotentInspect
Pause a recurring post: it stops creating occurrences and deletes its upcoming SCHEDULED post, preventing future scheduled occurrences until resume_recurring_post; an occurrence already publishing may still complete. Posts already published are kept. Slots that pass while paused are skipped, never published later. Use it when the user wants to hold the series; use delete_recurring_post to stop it for good. Deleting only the upcoming post with delete_post skips that one date and the series continues. Ids outside the workspace (the current one unless workspaceId names another) return "Recurring post not found". Returns the recurring post with status PAUSED and pauseReason USER.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Recurring post ID to pause, from list_recurring_posts | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | The paused recurring post: id, status PAUSED, pauseReason USER, the schedule, occurrenceCount, and the content and platforms. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial behavior beyond the annotations: the upcoming scheduled post is deleted, an in-flight publishing occurrence may still complete, already-published posts are kept, and skipped slots are never backfilled. It also documents the not-found error for out-of-workspace ids and the returned status/pauseReason, which the destructiveHint/idempotentHint annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and its immediate side effect, then the usage routing, then edge cases. Dense but every sentence carries distinct information; slightly long, though nothing is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description need not restate the return shape, and it still summarizes status PAUSED/pauseReason USER. Combined with annotations (destructive, idempotent) and full schema coverage, an agent has everything needed to call it correctly and predict consequences.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description still adds value by explaining workspace scoping (ids outside the current/other workspace yield 'Recurring post not found') and reinforcing that id comes from list_recurring_posts. This goes modestly beyond the schema's own parameter text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (pause a recurring post) and immediately clarifies the scope: it stops occurrence creation and deletes the upcoming SCHEDULED post. It explicitly contrasts with delete_recurring_post, resume_recurring_post, and delete_post, so an agent can distinguish it from every relevant sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use ('when the user wants to hold the series'), when-not ('use delete_recurring_post to stop it for good'), and the alternative for a one-off skip (delete_post). The selection logic between pause vs delete vs single-skip is fully spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pause_rss_feedPause RSS FeedAIdempotentInspect
Pause an RSS feed: it stops being checked until resume_rss_feed. Posts it already created stay, scheduled ones included; cancel those with delete_post. Ids outside the workspace return 404. Needs the posts.draft permission. Returns the feed with status PAUSED and pauseReason USER.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | RSS feed id from list_rss_feeds or create_rss_feed | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | The paused feed. The RSS feed: id, userId (the member it posts as, whoever last saved it), name, url, siteUrl, status (ACTIVE or PAUSED), pauseReason, lastError, postMode, publishDelayMinutes, contentMode, template, aiInstructions, includeImage, twitterKeepLinks, includeKeywords, excludeKeywords, maxPostsPerCheck, checkIntervalMinutes, targets, nextCheckAt, lastCheckedAt, lastPostedAt, createdAt and updatedAt. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare non-destructive and idempotent, and the description goes well beyond them: existing posts survive including scheduled ones, cancelling requires delete_post, out-of-workspace ids return 404, and posts.draft permission is required. That is exactly the extra context annotations cannot supply.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with the action and effect, then side effects, then error and permission, then return value. Every sentence supplies information an agent would otherwise have to guess.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers side effects, prerequisite permission, error behavior, and resulting state (status PAUSED, pauseReason USER) even though an output schema exists. Nothing material for a correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters are already documented, and the description's only added parameter-level fact is the 404 for ids outside the workspace. Baseline 3 applies since the schema carries the load.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Pause an RSS feed') plus the exact effect: it stops being checked until resume_rss_feed. This is unambiguously distinct from resume_rss_feed, check_rss_feed, and delete_rss_feed in the sibling list.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the counterpart tool (resume_rss_feed) as the way back and routes cleanup of scheduled posts to delete_post. Clear context for when to reach for this tool, though it stops short of stating an explicit 'do not use when you actually want X' exclusion.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
preview_rss_feedPreview RSS FeedARead-onlyInspect
Fetch an RSS or Atom feed without saving it and return its 5 newest items, each with text rendered from template, so the user can see what the posts would say before create_rss_feed. Fails with 400 when the URL is not a feed and 503 when it cannot be reached. Nothing is saved or posted. Needs the posts.draft permission.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Public http(s) URL of an RSS or Atom feed | |
| template | No | Post text with {title}, {link}, {description}, {author} and {feed} (max 2000 characters, default "{title}\n\n{link}"). The description, then the title, is shortened to fit each platform; the link is never cut | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with url, title, siteUrl and items: one { title, link, summary, publishedAt, imageUrl, text } per item, where text is the item rendered with template. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint and openWorldHint annotations, it states that nothing is saved or posted, discloses the 400 and 503 failure modes with their meanings, and names the required posts.draft permission. That is far more than the annotations convey, and nothing conflicts with them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with what it does and returns, then failure modes, then permission. There is no redundancy; each sentence adds information the agent needs (scope, output, errors, authorization).
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With read-only annotations and an output schema handling return values, the description still covers the things structured data can't: no persistence happens, the item count, HTTP error semantics, and the required permission. Nothing material is missing for a correct call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, and the schema already explains the template placeholders, truncation behavior, and workspaceId semantics in more detail than the description does. The description's 'text rendered from template' merely echoes that, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (fetch an RSS or Atom feed without saving it) plus the exact return shape: the 5 newest items with text rendered from the template. This separates it cleanly from create_rss_feed, get_rss_feed, and list_rss_feed_items.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly frames the use case as previewing what posts would say before calling create_rss_feed, which tells the agent when to pick this tool. It doesn't contrast with the closer siblings check_rss_feed or list_rss_feed_items, so the routing guidance is good but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
publish_draftPublish DraftADestructiveInspect
Publish a DRAFT post now or schedule it; SCHEDULED posts are accepted too, to reschedule or push live. Other statuses fail with "Post is not a draft". A future scheduledAt sets SCHEDULED for that time and queues nothing yet; a past one publishes now. Without scheduledAt, a draft whose planned date (the scheduledAt it was saved with) is still in the future is SCHEDULED for that date, and any other post (an undated draft, a planned date already past, a SCHEDULED post) publishes now. publishNow: true publishes now even when the draft has a planned date; sending it with scheduledAt fails with 400. Read the draft with get_post first and tell the user which of these will happen. Publishing now clears the stored scheduledAt, moves the post to PENDING and queues a publishing job per platform: content reaches the networks within moments and cannot be recalled. Fails if an account was disconnected or a TikTok entry lacks privacyLevel; fix with update_post first. Not for new content, use create_post. Check list_post_results afterwards for per-platform outcomes.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Post ID with status DRAFT (or SCHEDULED) | |
| timezone | No | IANA timezone stored with the post for display (e.g. "America/New_York"); it does not shift scheduledAt | UTC |
| publishNow | No | Publish now even when the draft has a planned date in the future. Sending it with scheduledAt fails with 400 | |
| scheduledAt | No | Absolute ISO 8601 instant (e.g. "2026-03-15T10:00:00Z"). A future time schedules for that time instead of the draft's planned date; a past time publishes now. Omit to schedule for the planned date when it is still in the future, and to publish now otherwise | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with postId, queuedPlatforms (platforms whose publishing job was queued; empty when scheduled for later), isScheduled, and scheduledAt. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes far beyond the destructiveHint/openWorldHint annotations by disclosing that publishing is irreversible ('cannot be recalled'), the concrete state transition (clears stored scheduledAt, moves to PENDING, queues a job per platform), timing expectations, and specific failure modes (disconnected account, TikTok entry missing privacyLevel, 400 on publishNow+scheduledAt). This is exactly the context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
High information density with zero filler and the primary behavior front-loaded, but the body is one long run-on block mixing the decision tree, side effects, and failure modes. Splitting the side effects and failure clauses into their own sentences/segments would improve scanability without losing content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers everything an agent needs for a destructive, open-world mutation: allowed input states, the full branch logic for scheduling vs. publishing now, side effects, blocking preconditions, remediation path, and where to check results. With an output schema already present, no return-value explanation is required.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description nonetheless adds decision semantics not obvious from the schema, e.g. that a past scheduledAt publishes now and that omitting scheduledAt falls back to the saved planned date. The publishNow/scheduledAt mutual exclusion is restated but reinforced with the error code.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (publish) and resource (a DRAFT/SCHEDULED post) and explicitly delineates the immediate-publish vs. schedule behaviors. It also names the sibling it is not ('Not for new content, use create_post'), so an agent can separate it from create_post and update_post without reading schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit preconditions ('Read the draft with get_post first and tell the user which of these will happen'), exclusions ('Other statuses fail with "Post is not a draft"'), and routes to the right follow-ups (update_post for fixes, create_post for new content, list_post_results for outcomes). The when-to-use decision tree is fully spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
refine_captionRefine CaptionAInspect
Rewrite an existing caption following an instruction, such as "shorter", "more playful" or "add a question at the end". Returns { caption }, the rewritten text; nothing is saved or posted. Send partialText to continue from a partly written caption. Pass platform to target that platform's character limit; check the returned text before posting. Needs the ai.generate permission, which Admin, Editor and Contributor hold and Viewer does not (403 permission_denied). Each call spends 2 of the member's AI credits (the member who signed in or created the key), refunded if generation fails, unless the member has their own AI provider key connected in AdaptlyPost. With no credits left the call fails: explain that generation is unavailable with the current credit balance and do not retry automatically. Costs the same as generate_caption.
| Name | Required | Description | Default |
|---|---|---|---|
| prompt | Yes | How the caption should change (max 2000 characters) | |
| platform | No | Platform the caption is for; generation targets that platform's character limit; check the returned text before posting | |
| partialText | No | A partly written caption to continue from (max 10000 characters) | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another | |
| originalText | Yes | The caption to rewrite (max 10000 characters) |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with caption: the rewritten text. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations already covering side-effect safety, the description adds substantial context: it states that no post is saved or published, discloses the ai.generate permission and the exact 403 error, quantifies the cost at 2 AI credits including refund behavior and own-provider-key exemption, and instructs the agent not to retry when credits are exhausted. It also confirms cost parity with generate_caption.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The text is front-loaded with the operation and return value, and each sentence carries operational value (permissions, credits, no-credit handling). The credit and permission material is dense and could be structured more crisply, but nothing is truly superfluous.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 5 parameters, full schema coverage, annotations, and an output schema, the description fills the remaining gaps an agent needs: side-effect expectations, permission requirements, credit cost and refund rules, failure handling, and the return shape. Nothing material is missing for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds workflow-level meaning beyond the schema: examples of prompt instructions and the specific use of partialText for continuing a partly written caption. The platform guidance largely duplicates the schema's own description, and workspaceId is not mentioned in the description, so it is not a full supplement.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific verb and resource ('Rewrite an existing caption following an instruction') and explicitly distinguishes it from generation of new captions by saying 'existing'. It also declares the return shape and that nothing is saved or posted, so an agent can tell exactly what this does versus siblings like generate_caption.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear usage contexts: pass partialText to continue a draft, pass platform to hit a character limit, and check the output before posting. It also covers failure paths (403 permission_denied, exhausted credits -> explain and do not retry). It stops short of an explicit 'use generate_caption instead for new captions' routing statement, so it is not a full when/when-not/alternatives guide.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_accountRemove AccountADestructiveInspect
Disconnect a social account from the workspace, the same way the Connectors page does: its stored tokens are deleted, it is taken off every pending and recurring post, and it stops counting toward the plan. Works for accounts in any status, so an unauthorized account can be cleaned up without reconnecting it. For Facebook only the named page goes; the other pages of the same login stay connected. Posts already published stay on the network. Confirm with the user first, naming the account. Bringing it back means connecting it again in AdaptlyPost (create_connect_link can send a link). Needs the accounts.manage permission, which Admin holds.
| Name | Required | Description | Default |
|---|---|---|---|
| accountId | Yes | The account id from list_accounts, or the Facebook pageId | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with id, platform, displayName, pageId for Facebook, and removed: true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true, but the description adds substantial context beyond them: token deletion, removal from pending and recurring posts, plan-count impact, published posts remaining on the network, and the Facebook per-page scoping rule. It also names the required permission (accounts.manage, held by Admin), which annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and side effects, and nearly every sentence carries distinct information (side effects, status applicability, FB scoping, published-post exception, permission). It is on the long side at seven clauses and the reconnection sentence could be tighter, but nothing is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, two-parameter tool with an output schema already covering return values, the description covers what an agent still needs: irreversibility path, blast radius on scheduled content, permission requirement, and the confirmation ritual. Nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents both parameters and the baseline is 3. The description earns a bump by clarifying a semantic ambiguity the schema only hints at: for Facebook the identifier is the page, not the login, so only that page is affected. It says nothing extra about workspaceId, leaving that entirely to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Disconnect a social account from the workspace') and immediately anchors it to a familiar surface ('the same way the Connectors page does'). It also carves out the Facebook page-vs-login distinction, which is what would otherwise be confused with account removal at the login level.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit conditions ('Works for accounts in any status, so an unauthorized account can be cleaned up without reconnecting it') and an explicit alternative path for reversal ('create_connect_link can send a link'), naming the sibling tool. It also states the required precondition of user confirmation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resume_recurring_postResume Recurring PostADestructiveInspect
Resume a PAUSED recurring post. It continues from the next occurrence after now; slots missed while paused are not published. The next occurrence is created as a SCHEDULED post about 24 hours before it goes out and then publishes to the networks, so confirm with the user first. If the series has no slot left (endsOn passed or maxOccurrences reached) it comes back ENDED instead. When pauseReason is CONNECTION_REMOVED, ACCESS_LOST, SUBSCRIPTION_INACTIVE or INVALID_CONTENT, fix the cause first or the series pauses again. Ids outside the workspace (the current one unless workspaceId names another) return "Recurring post not found". Returns the recurring post with its new status and nextOccurrenceAt.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Recurring post ID to resume, from list_recurring_posts | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | The resumed recurring post: id, status (ACTIVE, or ENDED when no slot is left), nextOccurrenceAt, the schedule, occurrenceCount, and the content and platforms. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations (destructiveHint=true, openWorldHint=true, readOnlyHint=false) mark this as a state-changing, outward-facing call, and the description adds substantial extra context: missed slots are not published, the next occurrence becomes a SCHEDULED post ~24h ahead, ENDED is returned when the series is exhausted, and workspace-scoped ids yield 'Recurring post not found'. This is exactly the behavioral disclosure the annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The most decision-relevant facts (what resume does, when confirmation is needed) are front-loaded, and every sentence carries operational information. It is dense rather than padded, though the string of pauseReason enum values and ending-status note makes it slightly long for two parameters.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description does not need to enumerate return fields, yet it still names the returned statuses and nextOccurrenceAt. For a destructive, world-affecting mutation tool with two fully documented parameters, nothing an agent needs to invoke it safely is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning beyond the field definitions by explaining that ids outside the named or current workspace return 'Recurring post not found' and by tying id provenance to list_recurring_posts. The workspace scoping rule is largely duplicated from the schema, keeping it short of a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Resume a PAUSED recurring post') and the scope is tightened by 'PAUSED', which clearly separates it from pause_recurring_post and the generic get/delete recurring post siblings. An agent can identify the operation without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear when-to-use context ('confirm with the user first', fix the cause when pauseReason is CONNECTION_REMOVED/ACCESS_LOST/etc.) and describes the outcome when no slot remains. It does not explicitly name pause_recurring_post as the inverse alternative, but the preconditions are well specified.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resume_rss_feedResume RSS FeedADestructiveInspect
Resume a paused RSS feed: the pause reason is cleared and the feed is checked within a minute, posting new items according to its post mode, so confirm with the user first. It then posts as the member resuming it, who needs the permission of its post mode. When pauseReason is ACCESS_LOST, SUBSCRIPTION_INACTIVE or CONNECTION_REMOVED, fix the cause first or the feed pauses again. Ids outside the workspace return 404. Needs the posts.draft permission.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | RSS feed id from list_rss_feeds or create_rss_feed | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | The resumed feed. The RSS feed: id, userId (the member it posts as, whoever last saved it), name, url, siteUrl, status (ACTIVE or PAUSED), pauseReason, lastError, postMode, publishDelayMinutes, contentMode, template, aiInstructions, includeImage, twitterKeepLinks, includeKeywords, excludeKeywords, maxPostsPerCheck, checkIntervalMinutes, targets, nextCheckAt, lastCheckedAt, lastPostedAt, createdAt and updatedAt. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description discloses significant side effects: the feed posts new items as the resuming member, requires the posts.draft permission, checks within a minute, and returns 404 for out-of-workspace ids. It also warns about recurring pause if the cause is not fixed, which is valuable behavioral context for a destructive/open-world operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core action and proceeds through confirmation, permission, pause-reason caveats, and workspace scoping without filler. Every sentence contributes actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the output schema and annotations, the description covers all key gaps: side effects, permissions, required confirmation, edge cases around pause reasons, and workspace scoping. An agent has enough to decide whether and how to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both id and workspaceId are already documented. The description only adds scoping detail (ids outside the workspace return 404) and does not explain parameter semantics beyond the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb (resume) and resource (paused RSS feed), and immediately clarifies the effect: clearing the pause reason and checking the feed within a minute. This clearly distinguishes it from sibling tools like pause_rss_feed and create_rss_feed.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says to confirm with the user first and gives conditions for when not to resume directly (pause reasons ACCESS_LOST, SUBSCRIPTION_INACTIVE, CONNECTION_REMOVED). It does not name an alternative sibling tool for those cases, but the when-to-use context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retry_failed_platformsRetry Failed PlatformsADestructiveInspect
Re-queue publishing for a post's FAILED platforms. platformIds takes platformId values from list_post_results, platform names such as "BLUESKY" (every failed row of that platform), or can be omitted to retry every failed row. Only rows with status FAILED are reset to PENDING and retried with the same content. A value matching neither a row id nor a platform of the post fails with "Unknown retry target"; with nothing failed among the matches the call fails with "No failed platforms to retry". The post moves to PUBLISHING and the retry is asynchronous, so check list_post_results for the outcome. Read each errorMessage first and retry once the cause is fixed (reconnected account, replaced media), not for a platform-side restriction, which will just fail again. Content cannot change on retry.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Post ID whose platforms failed | |
| platformIds | No | platformId values from list_post_results or platform names such as "BLUESKY". Omit to retry every FAILED row | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with postId, queuedPlatforms (platforms re-queued for publishing), and isScheduled: false. Outcomes arrive asynchronously in list_post_results. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (readOnlyHint=false, destructiveHint=true, openWorldHint=true) by disclosing state transitions (post moves to PUBLISHING), that retries are asynchronous, that content cannot change on retry, and the exact failure messages ('Unknown retry target', 'No failed platforms to retry'). This is unusually rich behavioral context for a mutation tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then constraints, failure modes, and post-call guidance in a logical order. Dense and slightly long, but virtually every clause carries distinct operational information rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described. With error cases, state transition, async caveat, and the follow-up tool all covered, an agent has everything needed to invoke this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description still adds value: it clarifies that platformIds accepts row ids, platform names, or omission, and specifies the failure behavior for values matching neither a row id nor a platform of the post.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: re-queue publishing for a post's FAILED platforms. It scopes exactly which rows are affected ('Only rows with status FAILED are reset to PENDING'), which distinguishes it from siblings like publish_draft or update_post without needing to open their schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use and when-not: read each errorMessage first and retry only once the cause is fixed (reconnected account, replaced media), not for a platform-side restriction, 'which will just fail again'. It also routes the agent to list_post_results for the outcome, covering the follow-up step.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
revoke_connect_linkRevoke Connect LinkADestructiveIdempotentInspect
Revoke a connect link so it stops working at once. Accounts already connected through it stay connected; remove them with remove_account. Needs the accounts.manage permission, which Admin holds. Returns { success: true }.
| Name | Required | Description | Default |
|---|---|---|---|
| token | Yes | The token returned by create_connect_link | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with success: true once the link is revoked. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and idempotentHint=true; the description goes further by disclosing the non-obvious side effect (existing connections persist), the auth requirement (accounts.manage, held by Admin), and the return payload. This is context an agent cannot get from the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with the action and its immediate effect, then side effects, permissions, and return value in descending order of importance. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive mutation with no output-schema ambiguity, the description covers effect, collateral behavior, required permission, and the follow-up tool, leaving nothing an agent needs before calling.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, including which tool produces the token ('returned by create_connect_link'), so the description correctly leaves parameters to the schema. It adds no extra meaning of its own, which is the baseline case.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Revoke a connect link') plus the immediate effect ('stops working at once'), which separates it from create_connect_link and from remove_account. The agent can identify what it does without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly scopes the behavior ('accounts already connected through it stay connected') and names the correct alternative ('remove them with remove_account'), so the common wrong-tool mistake is pre-empted. It also states the permission prerequisite.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_instagram_audioSearch Instagram AudioARead-onlyInspect
Search Instagram music and original sounds to add to a Reel. Returns { audio } with audioId, audioType, title, displayArtist (music), igUsername (original sounds), durationMs, coverArtworkUrl, profilePictureUrl, previewUrl (a temporary audio file, expires after about 1.5 days), instagramUrl and isAdsEligible. Leave out searchQuery to get what is trending. Only audio Meta has cleared for third-party publishing comes back, which can differ from what the Instagram app shows. Only works for Instagram accounts with supportsInstagramAudio: true in list_accounts; otherwise, or when Instagram rejects the search, it fails with 400. Pass the chosen audioId, with its title and artist, in instagramConfigs[].audio of create_post, update_post or bulk_schedule_posts. Nothing is posted.
| Name | Required | Description | Default |
|---|---|---|---|
| accountId | Yes | The Instagram account id from list_accounts | |
| audioType | Yes | music for licensed tracks, original_sound for sounds from other Instagram posts | |
| searchQuery | No | Keyword filter (max 100 characters). Leave out for trending audio | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with audio: one { audioId, audioType, title, displayArtist, igUsername, durationMs, coverArtworkUrl, profilePictureUrl, previewUrl, instagramUrl, isAdsEligible } per match. Pass audioId as instagramConfigs[].audio.audioId. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this read-only and open-world, and the description adds substantial detail beyond them: previewUrl expires in ~1.5 days, results are limited to Meta-cleared third-party-publishable audio which differs from the app, the supportsInstagramAudio gating, and the 400 failure mode. 'Nothing is posted' explicitly clarifies the read-only nature.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then return shape, then usage conditions. Dense but each clause carries information; the enumerated return fields are slightly list-heavy though they exist to help the agent pick an audioId.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers selection, prerequisites, failure modes, result interpretation, and downstream usage. An output schema exists, yet the description's brief enumeration aids picking the right audio to pass forward. Nothing needed to invoke correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds real behavioral meaning beyond the schema, notably that omitting searchQuery yields trending audio, which is an operational semantic not stated in the field itself.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource: searches Instagram music and original sounds for Reels. It clearly distinguishes the audio catalog from post-creation siblings, which it names explicitly as downstream consumers.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States when to use (to add audio to a Reel), a concrete alternative path ('leave out searchQuery to get what is trending'), prerequisites (account must have supportsInstagramAudio: true), and failure behavior (400 otherwise). It also routes the result into instagramConfigs[].audio of create_post/update_post/bulk_schedule_posts.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
test_webhookTest WebhookAInspect
Send one signed webhook.test event to the endpoint now and report how it answered, to check the URL and the signature check work. Needs the webhooks.manage permission.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Webhook id from list_webhooks or create_webhook | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with success, statusCode (the HTTP status the endpoint answered) and error when the delivery failed. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say it is not read-only, can reach open-world endpoints, and is not destructive. The description adds what actually happens: exactly one event, of type webhook.test, cryptographically signed, sent immediately, to the configured endpoint, then the endpoint's response is reported. It also adds an auth requirement. It stops short of describing side effects on the webhook record itself, such as failure state, so it falls short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with zero filler; the action and its verification purpose come first, and the permission requirement follows as the second essential fact.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With annotations and an output schema for the reported response, the description covers what an agent needs: what is sent, to where, and what authorization is required. It omits whether failed tests affect the webhook's stored state or whether repeat calls are rate-limited.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 100% description coverage for both parameters, including a detailed explanation of the workspaceId. The description adds nothing about the id parameter or workspace scope, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (send) and resource (a signed webhook.test event) plus its purpose (verify the URL and signature check). It is clearly distinguishable from list_webhooks, get_webhook, update_webhook, and delete_webhook without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a clear condition for use ('to check the URL and the signature check work') and states the prerequisite permission (webhooks.manage). It does not name an alternative or say when not to use it, but no sibling performs a comparable test call.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
trigger_analytics_syncTrigger Analytics SyncAIdempotentInspect
Ask AdaptlyPost to refresh analytics now instead of waiting for the scheduled sync: every connected account is queued and the last 7 days are re-read. Use it when the user just published and wants numbers, or when get_analytics_overview shows an old lastSyncedAt. Allowed once per workspace every 4 hours; inside the cooldown it returns queued: false with cooldownSecondsRemaining rather than an error, so do not retry in a loop. The sync runs in the background: poll get_analytics_sync_status until syncInProgress is false, then read the metrics again. Takes only the optional workspaceId and changes no content.
| Name | Required | Description | Default |
|---|---|---|---|
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with queued (true when a sync was started), message, and cooldownSecondsRemaining (seconds until the next allowed sync, null when queued). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses the rate limit (once per workspace every 4 hours), the non-error cooldown response shape (queued: false with cooldownSecondsRemaining), and the asynchronous background execution model with a required polling step. This is far beyond what the annotations state and resolves the tension with readOnlyHint=false by explaining the call changes no content.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the action and scope, then usage triggers, then the constraint, then the required follow-up. Four sentences, each carrying distinct operational information with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the description still covers the one behavior an agent must know (cooldown shape, async polling). Nothing needed to invoke it correctly or interpret the outcome is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the workspaceId semantics are already fully documented in the schema. The description only adds that workspaceId is optional and that no content is modified, which is minor added meaning. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('refresh analytics now'), plus precise scope: every connected account queued and the last 7 days re-read. Clearly distinguishable from read-only siblings like get_analytics_overview and get_analytics_timeseries.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit triggers ('when the user just published and wants numbers', or 'when get_analytics_overview shows an old lastSyncedAt') and names the follow-up tool get_analytics_sync_status. It also warns against a specific misuse: retrying in a loop inside the cooldown.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
unschedule_postUnschedule PostADestructiveIdempotentInspect
Take a DRAFT or SCHEDULED post off the calendar without deleting it: the post becomes an undated DRAFT (status DRAFT, scheduledAt null) and nothing publishes. Use it when the user wants to hold a scheduled post back; schedule it again later with publish_draft and a scheduledAt, and use delete_post only to drop it entirely. Any other status (PENDING, PUBLISHING, COMPLETED, FAILED, PARTIAL_FAILURE) fails with 400 because the post is already going out or out. Ids outside the workspace (the current one unless workspaceId names another) return 404. Safe to repeat on a post that is already an undated draft. Returns the post record.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Post ID with status DRAFT or SCHEDULED, from list_posts or create_post | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | The post record as an undated draft: id, status DRAFT, scheduledAt null, text, contentType, timezone, and platforms with per-target details. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond annotations: it documents the state machine (only DRAFT/SCHEDULED accepted, all other statuses 400), the 404 workspace-scoping rule, and the idempotency semantics ('safe to repeat on a post that is already an undated draft'). It also reassures that nothing publishes, which reconciles the destructiveHint=true flag with what is actually lost (only the scheduled date).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the primary effect and state transition, and every later sentence adds a distinct fact (alternatives, failure modes, idempotency, return). It is dense as one long paragraph; a short break before the error/idempotency clauses would aid scanning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 2-param mutation tool with an output schema, it covers preconditions, failure modes, workspace scoping, reversibility, repeat-safety, and return ('Returns the post record'). An agent can call it correctly without consulting anything else.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds error semantics per parameter: the id must be DRAFT or SCHEDULED (400 otherwise) and ids outside the named/current workspace yield 404. That explains consequences the schema text does not.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource plus the exact resulting state: 'the post becomes an undated DRAFT (status DRAFT, scheduledAt null) and nothing publishes.' It explicitly distinguishes itself from delete_post and publish_draft, so an agent can route correctly among the many post siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit when-to-use ('user wants to hold a scheduled post back'), the follow-up path ('schedule it again later with publish_draft and a scheduledAt'), and the exclusion ('use delete_post only to drop it entirely'). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_postUpdate PostADestructiveInspect
Update a DRAFT or SCHEDULED post in place; any other status fails with "Cannot edit post in current state", so published posts cannot be changed. Updates are partial: text, contentType, scheduledAt, timezone, thumbnail fields, firstComments and platformThumbnails you omit keep their values; sending firstComments or platformThumbnails replaces every stored entry. The exception is platforms: sending it rebuilds the post's target set from this request alone, so include every connection-id array and platform config you want to keep (TikTok with privacyLevel, Pinterest with its boardId or boardName); omitting platforms leaves accounts, configs, and media untouched. mediaUrls only take effect together with platforms; use publicUrl values from upload_media. On SCHEDULED posts new media is verified in storage. Returns the updated post record. Use publish_draft to change a draft's status, unschedule_post to take a scheduled post off the calendar, delete_post to cancel, and create_post for a new post.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Post ID to update (must be DRAFT or SCHEDULED) | |
| text | No | Updated text; omit to keep the current text. On LinkedIn, mention a company page with @[Page Name](urn:li:organization:<id>), using the page name exactly as LinkedIn shows it | |
| pageIds | No | Facebook page account ids from list_accounts (the account id; its pageId value is also accepted). Facebook has no connection-id array | |
| timezone | No | IANA timezone stored for display; does not shift scheduledAt | |
| mediaUrls | No | Replacement media URLs, applied only when platforms is also sent. Use publicUrl values from upload_media or get_upload_urls | |
| platforms | No | New target platforms. Sending this replaces every target, so also resend the connection-id arrays and platform configs to keep; omit to leave targets unchanged | |
| contentType | No | New content type; must match the media on the post. CAROUSEL takes 2 or more items in mediaUrls, up to 4 on TWITTER, BLUESKY and MASTODON, 5 on PINTEREST, 10 on INSTAGRAM, FACEBOOK, THREADS and TELEGRAM, 20 on LINKEDIN, 30 on TUMBLR and 35 on TIKTOK (JPEG or WebP photos only). INSTAGRAM and THREADS accept images and videos in the same carousel; every other platform takes images only, and YOUTUBE has no carousel. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters. DOCUMENT publishes one PDF, PPT, PPTX, DOC or DOCX file (max 100 MB, 300 pages) as a LinkedIn document post and is LinkedIn only: put exactly that one file in mediaUrls, target only LINKEDIN, and set the title with linkedinConfigs | |
| scheduledAt | No | New schedule time as an absolute ISO 8601 instant; omit to keep. On a DRAFT it sets the planned date and the post stays a draft. Moving a SCHEDULED post more than a minute into the past fails with 400; use publish_draft to publish now | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another | |
| thumbnailUrl | No | Video thumbnail as an https URL or an image data URI, used on every platform that takes one unless platformThumbnails overrides it | |
| firstComments | No | A comment posted from the same account right after the post goes out on a platform, one entry per platform. Available on LINKEDIN (1250 characters), TWITTER (280, as a reply), THREADS (500, as a reply), BLUESKY (300, as a reply), MASTODON (500, as a reply), YOUTUBE (10000), FACEBOOK (8000) and INSTAGRAM (2200). A platform the post does not go to, an empty or too long comment, a second entry for one platform, a platform that also has threadReplies, a private or made for kids YouTube video and Facebook or Instagram stories are refused with 400. The comment is posted about 10 seconds after the platform publishes (60 on YouTube) and retried up to 3 times; on X it is not retried, and a lifetime-deal account pays for it like any X post. A Facebook Page or Instagram account connected before first comments came to them must be reconnected once; until then its comment fails and firstCommentError says to reconnect. A comment that fails never fails the post: read firstCommentStatus and firstCommentError on the platform in get_post. On an update, sending the array replaces every first comment and omitting it keeps the stored ones | |
| mediaAltTexts | No | Alt text per image, in the same order as mediaUrls (max 1000 characters each; use "" to skip an image). Sent to X, Bluesky, Mastodon, Tumblr, LinkedIn, Facebook, Instagram and Threads; Pinterest uses the first one (cut to 500). TikTok, YouTube, Google Business Profile and videos ignore it. Applied only when platforms is also sent | |
| platformTexts | No | Per-platform caption overrides; applied to the targets sent in platforms | |
| threadReplies | No | Turns the post into a thread: the post opens it and each text is published as a reply to the one before, from the same account, one entry per platform. Available on TWITTER (280 characters per reply, or the account's own limit on X Premium), THREADS (500), BLUESKY (300) and MASTODON (500, or the instance's limit), up to 25 replies. A platform the post does not go to, an empty or too long reply, more than 25 replies, a second entry for one platform and a platform that also has a first comment are refused with 400. An entry with an empty texts array removes the thread. Replies start about 10 seconds after the platform publishes, 2 seconds apart. A failed run is retried up to 3 times and resumes after the last reply that went out; on X it is not retried, and a lifetime-deal account pays for each reply like any X post. A thread that fails never fails the post: read threadStatus, threadReplyIds and threadError on the platform in get_post. On an update, sending the array replaces every thread and omitting it keeps the stored ones | |
| tiktokConfigs | No | TikTok per-connection config. Each entry needs connectionId + privacyLevel at minimum | |
| tumblrConfigs | No | Tumblr per-blog config: tags, a title and a source link. connectionId must match an entry in tumblrConnectionIds | |
| youtubeConfigs | No | YouTube per-connection config with video title, tags, privacy, etc. | |
| facebookConfigs | No | Facebook per-page config: post type, shareToStory, video title, text background, and a grid or link carousel for several images. pageId must match an entry in pageIds | |
| linkedinConfigs | No | LinkedIn per-connection config: documentTitle names a DOCUMENT post, reshareOf reshares another LinkedIn post with the text as commentary. connectionId must match an entry in linkedinConnectionIds | |
| instagramConfigs | No | Instagram per-connection config: post type (FEED, REEL, STORY), shareToStory, collaborators, user tags, the AI info label, Reel audio, and trial reels | |
| pinterestConfigs | No | Pinterest per-connection config: the board to pin to, a pin title and a destination link. Get boardId from list_pinterest_boards for that connectionId, or pass the board name as boardName instead (not both); a board belongs to one Pinterest account. A boardName that matches no board or several fails with 400. Without either the pin goes to a board named AdaptlyPost | |
| twitterKeepLinks | No | Keep links in the X text clickable. X charges over 10 times more for a post with a link, so by default every link in X text is broken (example.com becomes example. com). Only AppSumo lifetime deals can turn this on, and a kept link costs 20 credits instead of 2. true on any other plan is refused with 400; it is ignored when the X text has no link | |
| platformThumbnails | No | A different thumbnail for one platform of a VIDEO post, one entry per platform. A platform without an entry uses the post-level thumbnailUrl and thumbnailTimestampMs. YOUTUBE, FACEBOOK, LINKEDIN and TELEGRAM take an image (thumbnailUrl); INSTAGRAM and PINTEREST take an image or a frame (thumbnailTimestampMs), the image winning when both are sent; TIKTOK takes only a frame. Posts that are not videos, Facebook and Instagram stories, a second entry for one platform and an entry the platform cannot use are refused with 400. On an update, sending the array replaces every override and omitting it keeps the stored ones | |
| tiktokConnectionIds | No | TikTok account connection IDs to post from | |
| tumblrConnectionIds | No | Tumblr blogs to post to, by the account id from list_accounts. TUMBLR takes text up to 32768 characters, up to 30 JPEG, PNG or GIF images (10 MB each) or one MP4 video (500 MB, up to 10 minutes), and alt text; it has no first comments, threads, per-platform thumbnails, image shapes or analytics | |
| blueskyConnectionIds | No | Bluesky account connection IDs to post from | |
| platformAspectRatios | No | Reframe every image of an IMAGE or CAROUSEL post to one shape on a platform, one entry per platform. INSTAGRAM takes SQUARE, PORTRAIT or LANDSCAPE (Instagram refuses 9:16 feed and carousel images); TIKTOK takes all four. Video posts, Instagram stories and a second entry for the same platform are refused with 400. Omit a platform to keep its images as uploaded. On an update it applies to the mediaUrls sent in the same request | |
| threadsConnectionIds | No | Threads account connection IDs to post from | |
| thumbnailTimestampMs | No | Video frame timestamp (ms) to use as the thumbnail, used by INSTAGRAM, PINTEREST and TIKTOK unless platformThumbnails overrides it | |
| twitterConnectionIds | No | X (Twitter) account connection IDs to post from | |
| youtubeConnectionIds | No | YouTube channel connection IDs to post from | |
| googleBusinessConfigs | No | Google Business Profile per-location config: update, event or offer, plus a button. connectionId must match an entry in googleBusinessConnectionIds. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters | |
| linkedinConnectionIds | No | LinkedIn account connection IDs to post from | |
| mastodonConnectionIds | No | Mastodon account connection IDs to post from | |
| telegramConnectionIds | No | Telegram channels and groups to post to, by the account id from list_accounts. TELEGRAM takes text up to 4096 characters, up to 10 images (JPEG, PNG or WebP, 10 MB each) or one MP4 or MOV video (50 MB); a caption over 1024 characters goes out as its own message after the media | |
| instagramConnectionIds | No | Instagram account connection IDs to post from | |
| pinterestConnectionIds | No | Pinterest account connection IDs to post from | |
| googleBusinessConnectionIds | No | Google Business Profile locations to post to, by the account id from list_accounts. A location without an entry in googleBusinessConfigs gets a STANDARD update |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | The updated post record: id, status (still DRAFT or SCHEDULED), text, contentType, scheduledAt, timezone, and platforms with per-target details. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as destructive and open-world, but the description adds crucial behavioral detail beyond them: partial-update defaults, destructive replacement semantics for platforms/firstComments/platformThumbnails, the mediaUrls dependency on platforms, and scheduled-post media verification. This is exactly the kind of consequence disclosure an agent needs before mutating a post.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The key status constraint and partial-update behavior are front-loaded, and every sentence carries useful information. However, it is a single dense paragraph covering many distinct behaviors, so scanability could be improved with light structuring.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, 38 parameters, full schema coverage, and an output schema, the description supplies the missing behavioral context: editability rules, replacement semantics, platform/media dependencies, and sibling routing. Nothing critical for a correct call is omitted.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description adds important cross-parameter semantics the schema alone does not fully emphasize: platforms rebuilds the entire target set, mediaUrls only applies with platforms, and firstComments/platformThumbnails replace all stored entries. It does not discuss every one of the 38 parameters, but it covers the highest-risk interactions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States the specific verb and resource (update a post) and immediately narrows scope to DRAFT or SCHEDULED status. It also names the sibling tools that handle adjacent operations, so an agent can distinguish it without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says when the tool cannot be used (published posts fail) and routes the agent to publish_draft, unschedule_post, delete_post, and create_post for the adjacent operations. The conditions for choosing alternatives are concrete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_rss_feedUpdate RSS FeedADestructiveInspect
Change an RSS feed's settings; only the fields sent change, and the URL cannot change. The feed then posts as the member making the change, so they need the permission of the resulting post mode, plus posts.others when someone else set the feed up. Switching postMode to SCHEDULE or PUBLISH means later items go out without further confirmation, so confirm with the user first. Ids outside the workspace return 404. Needs the posts.draft permission.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | RSS feed id from list_rss_feeds or create_rss_feed | |
| name | No | Name of the feed (max 120 characters). Defaults to the feed's title | |
| targets | No | Accounts every new item is posted to, 1 to 20. Feeds post to FACEBOOK, INSTAGRAM, THREADS, TWITTER, BLUESKY, LINKEDIN, MASTODON, TELEGRAM and GOOGLE_BUSINESS | |
| postMode | No | DRAFT creates a draft and needs posts.draft; SCHEDULE schedules the post publishDelayMinutes after the item is found and needs posts.schedule; PUBLISH publishes it right away and needs posts.publish | |
| template | No | Post text with {title}, {link}, {description}, {author} and {feed} (max 2000 characters, default "{title}\n\n{link}"). The description, then the title, is shortened to fit each platform; the link is never cut | |
| contentMode | No | TEMPLATE fills template; AI writes one caption per platform from the article, appends the link, spends 1 AI credit per platform per item and needs ai.generate | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another | |
| includeImage | No | Attach the item's image, or the article's preview image (default true) | |
| aiInstructions | No | Extra instructions for AI captions (max 1000 characters) | |
| excludeKeywords | No | Skip items whose title or summary contains one of these (up to 50) | |
| includeKeywords | No | Post only items whose title or summary contains one of these (up to 50) | |
| maxPostsPerCheck | No | New items posted per check, 1 to 10 (default 3). New items are posted oldest first; the rest wait for the next check | |
| twitterKeepLinks | No | Keep links in X posts clickable (default false). Lifetime-deal plans only; each X post with a link then costs more credits. Without it, links on X go out as plain text | |
| publishDelayMinutes | No | Minutes between finding an item and its post going out, 5 to 10080. Required when postMode is SCHEDULE | |
| checkIntervalMinutes | No | Minutes between checks: 15, 30, 60 (default), 180, 360, 720 or 1440 |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | The updated feed. The RSS feed: id, userId (the member it posts as, whoever last saved it), name, url, siteUrl, status (ACTIVE or PAUSED), pauseReason, lastError, postMode, publishDelayMinutes, contentMode, template, aiInstructions, includeImage, twitterKeepLinks, includeKeywords, excludeKeywords, maxPostsPerCheck, checkIntervalMinutes, targets, nextCheckAt, lastCheckedAt, lastPostedAt, createdAt and updatedAt. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds real context beyond the destructiveHint/openWorldHint annotations: patch semantics, the feed posting identity, permission escalation via posts.others, and the irreversible consequence of SCHEDULE/PUBLISH. The closing line 'Needs the posts.draft permission' is muddled because the schema ties posts.draft to DRAFT mode only, slightly undercutting an otherwise strong disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the mutation semantics, then permissions, then the dangerous side effect — a sound ordering with no filler sentences. The trailing permission sentence is redundant with the postMode semantics and is the one piece that does not earn its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 15-parameter mutation with an output schema and full schema descriptions, the description covers what the schema cannot: identity/permission requirements, patch behavior, 404 scoping, and the downstream consequence of an autonomous posting mode. Nothing an agent needs before calling is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description still adds meaning the schema lacks, namely that omitted fields are left untouched and that the URL is not editable, plus the actor/permission dependency for each postMode. It does not explain publishDelayMinutes or the AI credit cost beyond what the schema already says.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Change an RSS feed's settings') and immediately distinguishes the semantics from a full replace: partial patch, URL immutable. An agent can tell this apart from create_rss_feed, delete_rss_feed and pause_rss_feed without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear conditional guidance for the riskiest switch ('Switching postMode to SCHEDULE or PUBLISH ... confirm with the user first') and a precondition check ('Ids outside the workspace return 404'). It stops short of naming alternatives such as pause_rss_feed to stop posting entirely, so the routing is good but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_webhookUpdate WebhookAIdempotentInspect
Change a webhook endpoint's URL, or turn it off or back on with active. Turning on an endpoint that was turned off after failed deliveries starts sending again. Fails with 409 when the new URL is already registered. Needs the webhooks.manage permission.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Webhook id from list_webhooks or create_webhook | |
| url | No | New http(s) endpoint URL | |
| active | No | false stops deliveries, true resumes them | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | The updated webhook. The webhook: id, url, active, createdAt, updatedAt, lastSuccessAt, lastFailureAt and disabledAt (set when it was turned off after 20 failed deliveries in a row). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the tool as non-destructive and idempotent. The description adds useful context beyond that: the webhooks.manage permission requirement, the 409 conflict on duplicate URLs, and the behavior of reactivating an endpoint that was disabled after failed deliveries.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three compact sentences, front-loaded with the core action and followed by the most important behavioral caveats. Every sentence adds useful information without repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described. The description covers the mutation's key side effects, permission requirement, and a specific error case. Minor gaps remain around whether URL changes affect delivery state, but the definition is otherwise complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds meaning beyond the schema for active by explaining that re-enabling after failed deliveries resumes sending, and it ties url updates to a 409 duplicate-registration failure.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: changing a webhook endpoint's URL or toggling it with active. It is clearly distinct from create_webhook, delete_webhook, and test_webhook in practice, but it does not explicitly name sibling alternatives.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explains the two supported update modes: URL changes and active toggling. It also clarifies the reactivation case after failed deliveries, giving clear usage context, though it does not explicitly state when not to use this tool or name alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
upload_mediaUpload MediaADestructiveInspect
Upload images, videos or documents to AdaptlyPost storage and return public URLs for the mediaUrls of create_post, update_post, or bulk_schedule_posts. Three sources, combinable in one call: attachments (files the user attached in a ChatGPT conversation, which ChatGPT passes as file references; use this for every file attached in ChatGPT, whatever its size), urls (public https URLs the server streams straight into storage; private, internal and non-https addresses are refused) and files (base64 data, for small media attached in other apps; 30 MB decoded per call in total). Omitting all three returns an error. Accepts JPEG, PNG, WebP, GIF, MP4 and QuickTime, plus PDF, PPT, PPTX, DOC and DOCX for LinkedIn DOCUMENT posts, checked by file content (and, for Office files, the extension, so keep it in the name or URL); 50 MB per image, 100 MB per document, 250 MB per attachment or URL download. Stored files are public immediately, post or no post, so only upload media the user supplied or asked for. For base64 files over 30 MB use get_upload_urls and PUT the bytes yourself. Returns uploaded ({ publicUrl, key } per file) and mediaUrls; pass mediaUrls straight into the post. One publicUrl may be reused across any number of posts; the file is kept until the last post referencing it has published, so upload once and reuse rather than re-uploading per post.
| Name | Required | Description | Default |
|---|---|---|---|
| urls | No | Public https URLs of images, videos or documents to upload (e.g. ["https://example.com/photo.jpg", "https://example.com/deck.pdf"]) | |
| files | No | Direct file uploads as base64, 30 MB decoded per call in total. Use this for small media attached in apps other than ChatGPT; in ChatGPT use attachments | |
| attachments | No | Files the user attached in the ChatGPT conversation: images, videos or documents, up to 250 MB each. ChatGPT fills in each file reference; put every attached file the user wants to post here | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with uploaded (array of { publicUrl, key } per file) and mediaUrls (the public URLs ready to pass to create_post). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds important behavior beyond the annotations: stored files are public immediately, accepted formats are verified by content, Office files also require the extension, and files persist until the last referencing post publishes. This meaningfully complements the destructive/open-world annotations, though it could more directly acknowledge the destructive implication of permanent public exposure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose and then organized by source, limits, formats, and reuse behavior. It is long and dense, but nearly every sentence carries operational detail; the main cost is length rather than wasted content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a complex upload tool with four parameters, full schema coverage, and an output schema, the description covers source selection, limits, validation rules, return usage, and file reuse. An agent has enough information to choose the correct source and avoid common failures.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents each parameter, but the description adds cross-parameter semantics: the three sources are combinable, omitting all three is an error, and the 30 MB cap applies to decoded base64 across the whole call. It also clarifies that attachments should be used for ChatGPT files of any size, going beyond the schema text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: upload images, videos, or documents to AdaptlyPost storage and return public URLs. It immediately ties the output to the mediaUrls fields of create_post, update_post, and bulk_schedule_posts, making its role distinct from sibling tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly distinguishes the three input sources and when to use each: attachments for every file attached in ChatGPT regardless of size, urls for public https URLs, and files for small base64 media from other apps. It also states that omitting all three returns an error and directs oversized base64 uploads to get_upload_urls.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
validate_bulk_postsValidate Bulk PostsARead-onlyInspect
Dry-run bulk_schedule_posts: takes exactly the same input and returns one validation report per item, in input order, without creating, uploading or writing anything. Nothing is published, so no confirmation is needed. Each report has valid, outcome, requiredPermissions, issues, accounts and notChecked, as in validate_post. Fix the items with ERROR issues, then call bulk_schedule_posts. Needs the posts.draft permission.
| Name | Required | Description | Default |
|---|---|---|---|
| posts | Yes | 1 to 100 posts to schedule; each is created independently | |
| pageIds | No | Facebook page account ids from list_accounts (the account id; its pageId value is also accepted). Facebook has no connection-id array | |
| timezone | No | IANA timezone stored with every post for display; does not shift scheduledAt | UTC |
| platforms | Yes | Target platforms shared by every item. Each needs its connection-id array (pageIds for FACEBOOK, googleBusinessConnectionIds for GOOGLE_BUSINESS) | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another | |
| tiktokConfigs | No | TikTok per-connection config. Each entry needs connectionId + privacyLevel at minimum | |
| tumblrConfigs | No | Tumblr per-blog config: tags, a title and a source link. connectionId must match an entry in tumblrConnectionIds | |
| youtubeConfigs | No | YouTube per-connection config with video title, tags, privacy, etc. | |
| facebookConfigs | No | Facebook per-page config: post type, shareToStory, video title, text background, and a grid or link carousel for several images. pageId must match an entry in pageIds | |
| instagramConfigs | No | Instagram per-connection config: post type (FEED, REEL, STORY), shareToStory, collaborators, user tags, the AI info label, Reel audio, and trial reels | |
| pinterestConfigs | No | Pinterest per-connection config: the board to pin to, a pin title and a destination link. Get boardId from list_pinterest_boards for that connectionId, or pass the board name as boardName instead (not both); a board belongs to one Pinterest account. A boardName that matches no board or several fails with 400. Without either the pin goes to a board named AdaptlyPost | |
| tiktokConnectionIds | No | TikTok account connection IDs to post from | |
| tumblrConnectionIds | No | Tumblr blogs to post to, by the account id from list_accounts. TUMBLR takes text up to 32768 characters, up to 30 JPEG, PNG or GIF images (10 MB each) or one MP4 video (500 MB, up to 10 minutes), and alt text; it has no first comments, threads, per-platform thumbnails, image shapes or analytics | |
| blueskyConnectionIds | No | Bluesky account connection IDs to post from | |
| threadsConnectionIds | No | Threads account connection IDs to post from | |
| twitterConnectionIds | No | X (Twitter) account connection IDs to post from | |
| youtubeConnectionIds | No | YouTube channel connection IDs to post from | |
| googleBusinessConfigs | No | Google Business Profile per-location config: update, event or offer, plus a button. connectionId must match an entry in googleBusinessConnectionIds. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters | |
| linkedinConnectionIds | No | LinkedIn account connection IDs to post from | |
| mastodonConnectionIds | No | Mastodon account connection IDs to post from | |
| telegramConnectionIds | No | Telegram channels and groups to post to, by the account id from list_accounts. TELEGRAM takes text up to 4096 characters, up to 10 images (JPEG, PNG or WebP, 10 MB each) or one MP4 or MOV video (50 MB); a caption over 1024 characters goes out as its own message after the media | |
| instagramConnectionIds | No | Instagram account connection IDs to post from | |
| pinterestConnectionIds | No | Pinterest account connection IDs to post from | |
| googleBusinessConnectionIds | No | Google Business Profile locations to post to, by the account id from list_accounts. A location without an entry in googleBusinessConfigs gets a STANDARD update |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | An object with valid (true when every item is valid), totalValid, totalInvalid, and results: one { index, report } per item, where report has the validate_post shape. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false, and openWorldHint=true, but the description adds important behavioral context beyond them: nothing is created, uploaded, written, or published; no confirmation is required; reports are returned in input order; and the posts.draft permission is required. These details materially help an agent understand side effects and authorization.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded: it first states the dry-run relationship and no-write behavior, then explains the report shape and next step. Every sentence contributes either scope, safety, output expectation, or workflow guidance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, the extensive input schema, the existing output schema, and the annotations, the description is complete enough to invoke correctly. It explains the dry-run contract, output report fields, permission requirement, and follow-up action without redundantly restating schema details.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the parameters are already well documented in the schema. The description correctly says it takes exactly the same input as bulk_schedule_posts and names the report fields, but it does not add parameter-level meaning beyond the schema. A baseline 3 is appropriate when the schema carries parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: it dry-runs bulk_schedule_posts with exactly the same input and returns one validation report per item. It explicitly distinguishes this from the actual scheduling sibling and from validate_post, so an agent can identify the tool's role without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit workflow: use this to validate, fix items with ERROR issues, then call bulk_schedule_posts. It also states that no confirmation is needed because nothing is published, which directly informs when and how to invoke it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
validate_postValidate PostARead-onlyInspect
Dry-run create_post: takes exactly the same input and runs every check creating the post would run, plus the ones that usually fail only at publish time (TikTok creator limits, YouTube upload quota, expired tokens, Pinterest boards, X credits), without creating a post, uploading media or writing anything. Nothing is published, so no confirmation is needed. Always returns a report: valid is false when any issue has severity ERROR. Issues tied to one account are listed under that account in accounts (status READY, WARNING or BLOCKED); the rest are in issues, each with a stable code, severity and message. outcome says what creating the post would do (DRAFT, SCHEDULED or PUBLISH_NOW), and requiredPermissions names the permissions it would need; a missing one shows up as a PERMISSION_DENIED issue. notChecked lists what only the platform decides at publish time, so valid: true is not a guarantee. Fix every ERROR, then call create_post with the same input. Needs the posts.draft permission.
| Name | Required | Description | Default |
|---|---|---|---|
| text | No | Default post text shared across platforms. On LinkedIn, mention a company page with @[Page Name](urn:li:organization:<id>), using the page name exactly as LinkedIn shows it | |
| pageIds | No | Facebook page account ids from list_accounts (the account id; its pageId value is also accepted). Facebook has no connection-id array | |
| timezone | No | IANA timezone stored with the post for display (e.g. "America/New_York"); it does not shift scheduledAt | UTC |
| mediaUrls | No | Media URLs to attach. Use publicUrl values from upload_media or get_upload_urls; the same publicUrl may be reused across posts. Do not reuse mediaUrls read back from a published post, which may be expiring platform links | |
| platforms | No | Target platforms (e.g. ["LINKEDIN", "TWITTER"]). Each one needs its matching connection-id array (pageIds for FACEBOOK, googleBusinessConnectionIds for GOOGLE_BUSINESS) filled with ids from list_accounts. Optional when accountIds is sent | |
| accountIds | No | Account ids (or Facebook pageIds) from list_accounts to post to. AdaptlyPost adds each account's platform to platforms and its id to the matching connection-id array, so you can send these instead of platforms and the per-platform arrays, or alongside them. An id not connected to the workspace fails with 400 | |
| recurrence | No | Repeat the post on a schedule the user asked for, and confirm that schedule with them first. Needs a future scheduledAt, which becomes the first post and sets the time of day in timezone. Cannot be combined with saveAsDraft or TIKTOK. Missed slots, for example while paused, are skipped and never published late. The user can pause or stop the series at any time with pause_recurring_post or delete_recurring_post; list_recurring_posts shows it | |
| contentType | Yes | Content type: TEXT, IMAGE, VIDEO, CAROUSEL, or DOCUMENT. Must match mediaUrls. CAROUSEL takes 2 or more items in mediaUrls, up to 4 on TWITTER, BLUESKY and MASTODON, 5 on PINTEREST, 10 on INSTAGRAM, FACEBOOK, THREADS and TELEGRAM, 20 on LINKEDIN, 30 on TUMBLR and 35 on TIKTOK (JPEG or WebP photos only). INSTAGRAM and THREADS accept images and videos in the same carousel; every other platform takes images only, and YOUTUBE has no carousel. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters. TELEGRAM takes text up to 4096 characters, up to 10 images (JPEG, PNG or WebP, 10 MB each) or one MP4 or MOV video (50 MB); a caption over 1024 characters goes out as its own message after the media. DOCUMENT publishes one PDF, PPT, PPTX, DOC or DOCX file (max 100 MB, 300 pages) as a LinkedIn document post and is LinkedIn only: put exactly that one file in mediaUrls, target only LINKEDIN, and set the title with linkedinConfigs | |
| saveAsDraft | No | Save as DRAFT instead of publishing or scheduling; publish later with publish_draft. A scheduledAt sent with it is stored as the draft's planned date, and publish_draft schedules the draft for that date | |
| scheduledAt | No | Absolute ISO 8601 instant to schedule (e.g. "2026-03-15T10:00:00Z"). Omit to post immediately; a past time also posts immediately. With saveAsDraft it is the draft's planned date instead: nothing is scheduled, and publish_draft without a date later schedules the draft for it | |
| workspaceId | No | Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another | |
| thumbnailUrl | No | Video thumbnail as an https URL or an image data URI, used on every platform that takes one unless platformThumbnails overrides it | |
| firstComments | No | A comment posted from the same account right after the post goes out on a platform, one entry per platform. Available on LINKEDIN (1250 characters), TWITTER (280, as a reply), THREADS (500, as a reply), BLUESKY (300, as a reply), MASTODON (500, as a reply), YOUTUBE (10000), FACEBOOK (8000) and INSTAGRAM (2200). A platform the post does not go to, an empty or too long comment, a second entry for one platform, a platform that also has threadReplies, a private or made for kids YouTube video and Facebook or Instagram stories are refused with 400. The comment is posted about 10 seconds after the platform publishes (60 on YouTube) and retried up to 3 times; on X it is not retried, and a lifetime-deal account pays for it like any X post. A Facebook Page or Instagram account connected before first comments came to them must be reconnected once; until then its comment fails and firstCommentError says to reconnect. A comment that fails never fails the post: read firstCommentStatus and firstCommentError on the platform in get_post. On an update, sending the array replaces every first comment and omitting it keeps the stored ones | |
| mediaAltTexts | No | Alt text per image, in the same order as mediaUrls (max 1000 characters each; use "" to skip an image). Sent to X, Bluesky, Mastodon, Tumblr, LinkedIn, Facebook, Instagram and Threads; Pinterest uses the first one (cut to 500). TikTok, YouTube, Google Business Profile and videos ignore it | |
| platformTexts | No | Per-platform caption overrides | |
| threadReplies | No | Turns the post into a thread: the post opens it and each text is published as a reply to the one before, from the same account, one entry per platform. Available on TWITTER (280 characters per reply, or the account's own limit on X Premium), THREADS (500), BLUESKY (300) and MASTODON (500, or the instance's limit), up to 25 replies. A platform the post does not go to, an empty or too long reply, more than 25 replies, a second entry for one platform and a platform that also has a first comment are refused with 400. An entry with an empty texts array removes the thread. Replies start about 10 seconds after the platform publishes, 2 seconds apart. A failed run is retried up to 3 times and resumes after the last reply that went out; on X it is not retried, and a lifetime-deal account pays for each reply like any X post. A thread that fails never fails the post: read threadStatus, threadReplyIds and threadError on the platform in get_post. On an update, sending the array replaces every thread and omitting it keeps the stored ones | |
| tiktokConfigs | No | TikTok per-connection config. Each entry needs connectionId + privacyLevel at minimum | |
| tumblrConfigs | No | Tumblr per-blog config: tags, a title and a source link. connectionId must match an entry in tumblrConnectionIds | |
| youtubeConfigs | No | YouTube per-connection config with video title, tags, privacy, etc. | |
| facebookConfigs | No | Facebook per-page config: post type, shareToStory, video title, text background, and a grid or link carousel for several images. pageId must match an entry in pageIds | |
| linkedinConfigs | No | LinkedIn per-connection config: documentTitle names a DOCUMENT post, reshareOf reshares another LinkedIn post with the text as commentary. connectionId must match an entry in linkedinConnectionIds | |
| instagramConfigs | No | Instagram per-connection config: post type (FEED, REEL, STORY), shareToStory, collaborators, user tags, the AI info label, Reel audio, and trial reels | |
| pinterestConfigs | No | Pinterest per-connection config: the board to pin to, a pin title and a destination link. Get boardId from list_pinterest_boards for that connectionId, or pass the board name as boardName instead (not both); a board belongs to one Pinterest account. A boardName that matches no board or several fails with 400. Without either the pin goes to a board named AdaptlyPost | |
| twitterKeepLinks | No | Keep links in the X text clickable. X charges over 10 times more for a post with a link, so by default every link in X text is broken (example.com becomes example. com). Only AppSumo lifetime deals can turn this on, and a kept link costs 20 credits instead of 2. true on any other plan is refused with 400; it is ignored when the X text has no link | |
| platformThumbnails | No | A different thumbnail for one platform of a VIDEO post, one entry per platform. A platform without an entry uses the post-level thumbnailUrl and thumbnailTimestampMs. YOUTUBE, FACEBOOK, LINKEDIN and TELEGRAM take an image (thumbnailUrl); INSTAGRAM and PINTEREST take an image or a frame (thumbnailTimestampMs), the image winning when both are sent; TIKTOK takes only a frame. Posts that are not videos, Facebook and Instagram stories, a second entry for one platform and an entry the platform cannot use are refused with 400. On an update, sending the array replaces every override and omitting it keeps the stored ones | |
| tiktokConnectionIds | No | TikTok account connection IDs to post from | |
| tumblrConnectionIds | No | Tumblr blogs to post to, by the account id from list_accounts. TUMBLR takes text up to 32768 characters, up to 30 JPEG, PNG or GIF images (10 MB each) or one MP4 video (500 MB, up to 10 minutes), and alt text; it has no first comments, threads, per-platform thumbnails, image shapes or analytics | |
| blueskyConnectionIds | No | Bluesky account connection IDs to post from | |
| platformAspectRatios | No | Reframe every image of an IMAGE or CAROUSEL post to one shape on a platform, one entry per platform. INSTAGRAM takes SQUARE, PORTRAIT or LANDSCAPE (Instagram refuses 9:16 feed and carousel images); TIKTOK takes all four. Video posts, Instagram stories and a second entry for the same platform are refused with 400. Omit a platform to keep its images as uploaded. On an update it applies to the mediaUrls sent in the same request | |
| threadsConnectionIds | No | Threads account connection IDs to post from | |
| thumbnailTimestampMs | No | Video frame timestamp (ms) to use as the thumbnail, used by INSTAGRAM, PINTEREST and TIKTOK unless platformThumbnails overrides it | |
| twitterConnectionIds | No | X (Twitter) account connection IDs to post from | |
| youtubeConnectionIds | No | YouTube channel connection IDs to post from | |
| googleBusinessConfigs | No | Google Business Profile per-location config: update, event or offer, plus a button. connectionId must match an entry in googleBusinessConnectionIds. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters | |
| linkedinConnectionIds | No | LinkedIn account connection IDs to post from | |
| mastodonConnectionIds | No | Mastodon account connection IDs to post from | |
| telegramConnectionIds | No | Telegram channels and groups to post to, by the account id from list_accounts. TELEGRAM takes text up to 4096 characters, up to 10 images (JPEG, PNG or WebP, 10 MB each) or one MP4 or MOV video (50 MB); a caption over 1024 characters goes out as its own message after the media | |
| instagramConnectionIds | No | Instagram account connection IDs to post from | |
| pinterestConnectionIds | No | Pinterest account connection IDs to post from | |
| googleBusinessConnectionIds | No | Google Business Profile locations to post to, by the account id from list_accounts. A location without an entry in googleBusinessConfigs gets a STANDARD update |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | A validation report: valid, outcome (DRAFT, SCHEDULED or PUBLISH_NOW), scheduledAt, requiredPermissions, issues (each { code, severity ERROR or WARNING, message, platform, connectionId }), accounts (each { platform, connectionId, accountName, status READY, WARNING or BLOCKED, issues }), and notChecked (each { code, message }). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations (readOnlyHint true, destructiveHint false) already declare the safety profile and the description is fully consistent with them while adding substantial detail on top: which extra pre-publish checks run (TikTok creator limits, YouTube quota, expired tokens, Pinterest boards, X credits), that nothing is written, and the crucial caveat that 'notChecked lists what only the platform decides at publish time, so valid: true is not a guarantee.' That caveat is exactly the kind of nuance annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded correctly — purpose and the create_post relationship come first, reporting semantics after. It is a single dense paragraph where every sentence carries information (checks run, report shape, fix-then-create loop), but the run-on parenthetical lists of platform failures and the return-field enumeration make it heavier than necessary when an output schema already documents the report.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 40 parameters, nested config objects, a real output schema and an open-world external dependency surface, the description covers everything an agent needs: prerequisites (posts.draft), the fix-iterate loop, how account-scoped issues differ from global issues, and the honesty boundary around publish-time checks. The return-value detail is partly redundant with the output schema but reinforces interpretation rather than substituting for it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% across 40 parameters, so the baseline is 3. The description earns the extra point by establishing that the input surface is identical to create_post ('takes exactly the same input'), which tells the agent it can reuse the payload it already built rather than assuming dry-run-specific fields. It does not annotate individual parameters, but it does not need to.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a precise verb+resource framing: 'Dry-run create_post: takes exactly the same input and runs every check creating the post would run' — the agent immediately knows this is the validation twin of create_post. It further specifies what is checked and what is deliberately not produced (no post, no media upload, no writes), so it is distinguishable from create_post and validate_bulk_posts without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit workflow routing: 'Fix every ERROR, then call create_post with the same input' names the alternative and the exact condition that selects it. It also states 'no confirmation is needed' and notes the posts.draft permission, removing the two most likely reasons an agent would hesitate or ask the user first.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
- Changed
create_post2 fields changed- changed
Input schema / properties / saveAsDraft / descriptionPrevious value: -"Save as DRAFT instead of publishing or scheduling; publish later with publish_draft"New value: +"Save as DRAFT instead of publishing or scheduling; publish later with publish_draft. A scheduledAt sent with it is stored as the draft's planned date, and publish_draft schedules the draft for that date" - changed
Input schema / properties / scheduledAt / descriptionPrevious value: -"Absolute ISO 8601 instant to schedule (e.g. \"2026-03-15T10:00:00Z\"). Omit to post immediately; a past time also posts immediately"New value: +"Absolute ISO 8601 instant to schedule (e.g. \"2026-03-15T10:00:00Z\"). Omit to post immediately; a past time also posts immediately. With saveAsDraft it is the draft's planned date instead: nothing is scheduled, and publish_draft without a date later schedules the draft for it"
- Changed
publish_draft2 fields changed- added
Input schema / properties / publishNowAdded value: +{ + "description": "Publish now even when the draft has a planned date in the future. Sending it with scheduledAt fails with 400", + "type": "boolean" +} - changed
Input schema / properties / scheduledAt / descriptionPrevious value: -"Absolute ISO 8601 instant (e.g. \"2026-03-15T10:00:00Z\"). Omit, or pass a past time, to publish now"New value: +"Absolute ISO 8601 instant (e.g. \"2026-03-15T10:00:00Z\"). A future time schedules for that time instead of the draft's planned date; a past time publishes now. Omit to schedule for the planned date when it is still in the future, and to publish now otherwise"
- Changed
update_post1 field changed- changed
Input schema / properties / scheduledAt / descriptionPrevious value: -"New schedule time as an absolute ISO 8601 instant; omit to keep. Moving a SCHEDULED post more than a minute into the past fails with 400; use publish_draft to publish now"New value: +"New schedule time as an absolute ISO 8601 instant; omit to keep. On a DRAFT it sets the planned date and the post stays a draft. Moving a SCHEDULED post more than a minute into the past fails with 400; use publish_draft to publish now"
- Changed
validate_post2 fields changed- changed
Input schema / properties / saveAsDraft / descriptionPrevious value: -"Save as DRAFT instead of publishing or scheduling; publish later with publish_draft"New value: +"Save as DRAFT instead of publishing or scheduling; publish later with publish_draft. A scheduledAt sent with it is stored as the draft's planned date, and publish_draft schedules the draft for that date" - changed
Input schema / properties / scheduledAt / descriptionPrevious value: -"Absolute ISO 8601 instant to schedule (e.g. \"2026-03-15T10:00:00Z\"). Omit to post immediately; a past time also posts immediately"New value: +"Absolute ISO 8601 instant to schedule (e.g. \"2026-03-15T10:00:00Z\"). Omit to post immediately; a past time also posts immediately. With saveAsDraft it is the draft's planned date instead: nothing is scheduled, and publish_draft without a date later schedules the draft for it"
7 tool updates
- Changed
bulk_schedule_posts1 field changed- changed
Input schema / properties / tumblrConnectionIds / descriptionPrevious value: -"Tumblr blog account ids from list_accounts to post to"New value: +"Tumblr blogs to post to, by the account id from list_accounts. TUMBLR takes text up to 32768 characters, up to 30 JPEG, PNG or GIF images (10 MB each) or one MP4 video (500 MB, up to 10 minutes), and alt text; it has no first comments, threads, per-platform thumbnails, image shapes or analytics"
- Changed
create_post1 field changed- changed
Input schema / properties / tumblrConnectionIds / descriptionPrevious value: -"Tumblr blog account ids from list_accounts to post to"New value: +"Tumblr blogs to post to, by the account id from list_accounts. TUMBLR takes text up to 32768 characters, up to 30 JPEG, PNG or GIF images (10 MB each) or one MP4 video (500 MB, up to 10 minutes), and alt text; it has no first comments, threads, per-platform thumbnails, image shapes or analytics"
- Changed
get_upload_urls1 field changed- changed
Input schema / properties / files / items / properties / mimeType / enumPrevious value: -[ - "image/jpeg", - "image/png", - "image/webp", - "video/mp4", - "video/quicktime", - "application/pdf", - "application/vnd.ms-powerpoint", - "application/vnd.openxmlformats-officedocument.presentationml.presentation", - "application/msword", - "application/vnd.openxmlformats-officedocument.wordprocessingml.document" -]New value: +[ + "image/jpeg", + "image/png", + "image/webp", + "image/gif", + "video/mp4", + "video/quicktime", + "application/pdf", + "application/vnd.ms-powerpoint", + "application/vnd.openxmlformats-officedocument.presentationml.presentation", + "application/msword", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document" +]
- Changed
update_post1 field changed- changed
Input schema / properties / tumblrConnectionIds / descriptionPrevious value: -"Tumblr blog account ids from list_accounts to post to"New value: +"Tumblr blogs to post to, by the account id from list_accounts. TUMBLR takes text up to 32768 characters, up to 30 JPEG, PNG or GIF images (10 MB each) or one MP4 video (500 MB, up to 10 minutes), and alt text; it has no first comments, threads, per-platform thumbnails, image shapes or analytics"
- Changed
upload_media1 field changed- changed
Input schema / properties / files / items / properties / mimeType / enumPrevious value: -[ - "image/jpeg", - "image/png", - "image/webp", - "video/mp4", - "video/quicktime", - "application/pdf", - "application/vnd.ms-powerpoint", - "application/vnd.openxmlformats-officedocument.presentationml.presentation", - "application/msword", - "application/vnd.openxmlformats-officedocument.wordprocessingml.document" -]New value: +[ + "image/jpeg", + "image/png", + "image/webp", + "image/gif", + "video/mp4", + "video/quicktime", + "application/pdf", + "application/vnd.ms-powerpoint", + "application/vnd.openxmlformats-officedocument.presentationml.presentation", + "application/msword", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document" +]
- Changed
validate_bulk_posts1 field changed- changed
Input schema / properties / tumblrConnectionIds / descriptionPrevious value: -"Tumblr blog account ids from list_accounts to post to"New value: +"Tumblr blogs to post to, by the account id from list_accounts. TUMBLR takes text up to 32768 characters, up to 30 JPEG, PNG or GIF images (10 MB each) or one MP4 video (500 MB, up to 10 minutes), and alt text; it has no first comments, threads, per-platform thumbnails, image shapes or analytics"
- Changed
validate_post1 field changed- changed
Input schema / properties / tumblrConnectionIds / descriptionPrevious value: -"Tumblr blog account ids from list_accounts to post to"New value: +"Tumblr blogs to post to, by the account id from list_accounts. TUMBLR takes text up to 32768 characters, up to 30 JPEG, PNG or GIF images (10 MB each) or one MP4 video (500 MB, up to 10 minutes), and alt text; it has no first comments, threads, per-platform thumbnails, image shapes or analytics"
36 tool updates
- Changed
bulk_schedule_posts19 fields changed- changed
Input schema / properties / facebookConfigs / descriptionPrevious value: -"Facebook per-page config: post type, shareToStory, video title and text background. pageId must match an entry in pageIds"New value: +"Facebook per-page config: post type, shareToStory, video title, text background, and a grid or link carousel for several images. pageId must match an entry in pageIds" - changed
Input schema / properties / instagramConfigs / descriptionPrevious value: -"Instagram per-connection config: post type (FEED, REEL, STORY), shareToStory, collaborators, Reel audio, and trial reels"New value: +"Instagram per-connection config: post type (FEED, REEL, STORY), shareToStory, collaborators, user tags, the AI info label, Reel audio, and trial reels" - changed
Input schema / properties / platforms / items / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON", - "GOOGLE_BUSINESS" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS", + "TUMBLR", + "TELEGRAM" +] - changed
Input schema / properties / posts / items / properties / contentType / descriptionPrevious value: -"TEXT, IMAGE, VIDEO, or CAROUSEL; must match mediaUrls. DOCUMENT posts cannot be bulk scheduled; use create_post. CAROUSEL takes 2 or more items in mediaUrls, up to 4 on TWITTER, BLUESKY and MASTODON, 5 on PINTEREST, 10 on INSTAGRAM, FACEBOOK and THREADS, 20 on LINKEDIN and 35 on TIKTOK (JPEG or WebP photos only). INSTAGRAM and THREADS accept images and videos in the same carousel; every other platform takes images only, and YOUTUBE has no carousel. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters"New value: +"TEXT, IMAGE, VIDEO, or CAROUSEL; must match mediaUrls. DOCUMENT posts cannot be bulk scheduled; use create_post. CAROUSEL takes 2 or more items in mediaUrls, up to 4 on TWITTER, BLUESKY and MASTODON, 5 on PINTEREST, 10 on INSTAGRAM, FACEBOOK, THREADS and TELEGRAM, 20 on LINKEDIN, 30 on TUMBLR and 35 on TIKTOK (JPEG or WebP photos only). INSTAGRAM and THREADS accept images and videos in the same carousel; every other platform takes images only, and YOUTUBE has no carousel. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters. TELEGRAM takes text up to 4096 characters, up to 10 images (JPEG, PNG or WebP, 10 MB each) or one MP4 or MOV video (50 MB); a caption over 1024 characters goes out as its own message after the media" - added
Input schema / properties / posts / items / properties / facebookConfigs / items / properties / carouselCardsAdded value: +{ + "description": "One card per image, in the same order as the media, used when imageLayout is CAROUSEL. Facebook only shows your image, title and description on a card whose link points to a website the Page owns; for any other link the post fails with the error Facebook returns", + "items": { + "additionalProperties": false, + "properties": { + "description": { + "description": "The line under the headline, such as a price or the domain. Without it Facebook uses the linked page", + "maxLength": 200, + "type": "string" + }, + "link": { + "description": "The http or https URL the card opens", + "maxLength": 2048, + "type": "string" + }, + "title": { + "description": "The card's headline. Without it Facebook uses the linked page's title", + "maxLength": 100, + "type": "string" + } + }, + "required": [ + "link" + ], + "type": "object" + }, + "maxItems": 5, + "type": "array" +} - added
Input schema / properties / posts / items / properties / facebookConfigs / items / properties / imageLayoutAdded value: +{ + "description": "How a post with several images shows on Facebook. GRID is a photo grid. CAROUSEL is a swipeable carousel where each image is a card with its own link, and needs 2 to 5 images, no videos, postType FEED and one carouselCards entry per image; anything else is refused with 400", + "enum": [ + "GRID", + "CAROUSEL" + ], + "type": "string" +} - changed
Input schema / properties / posts / items / properties / firstComments / descriptionPrevious value: -"A comment posted from the same account right after the post goes out on a platform, one entry per platform. Available on LINKEDIN (1250 characters), TWITTER (280, as a reply), THREADS (500, as a reply), BLUESKY (300, as a reply), MASTODON (500, as a reply) and YOUTUBE (10000). A platform the post does not go to, an empty or too long comment, a second entry for one platform, a private or made for kids YouTube video and Facebook or Instagram stories are refused with 400. The comment is posted about 10 seconds after the platform publishes (60 on YouTube) and retried up to 3 times; on X it is not retried, and a lifetime-deal account pays for it like any X post. A comment that fails never fails the post: read firstCommentStatus and firstCommentError on the platform in get_post. On an update, sending the array replaces every first comment and omitting it keeps the stored ones"New value: +"A comment posted from the same account right after the post goes out on a platform, one entry per platform. Available on LINKEDIN (1250 characters), TWITTER (280, as a reply), THREADS (500, as a reply), BLUESKY (300, as a reply), MASTODON (500, as a reply), YOUTUBE (10000), FACEBOOK (8000) and INSTAGRAM (2200). A platform the post does not go to, an empty or too long comment, a second entry for one platform, a platform that also has threadReplies, a private or made for kids YouTube video and Facebook or Instagram stories are refused with 400. The comment is posted about 10 seconds after the platform publishes (60 on YouTube) and retried up to 3 times; on X it is not retried, and a lifetime-deal account pays for it like any X post. A Facebook Page or Instagram account connected before first comments came to them must be reconnected once; until then its comment fails and firstCommentError says to reconnect. A comment that fails never fails the post: read firstCommentStatus and firstCommentError on the platform in get_post. On an update, sending the array replaces every first comment and omitting it keeps the stored ones" - changed
Input schema / properties / posts / items / properties / firstComments / items / properties / platform / enumPrevious value: -[ - "LINKEDIN", - "TWITTER", - "THREADS", - "BLUESKY", - "MASTODON", - "YOUTUBE" -]New value: +[ + "LINKEDIN", + "TWITTER", + "THREADS", + "BLUESKY", + "MASTODON", + "YOUTUBE", + "FACEBOOK", + "INSTAGRAM" +] - added
Input schema / properties / posts / items / properties / instagramConfigs / items / properties / aiGeneratedAdded value: +{ + "description": "Disclose that the post was made or edited with AI. Instagram shows its \"AI info\" label on the post. Works on images, carousels, reels and stories, and a story made with shareToStory carries the label too. Omit it or send false for no label", + "type": "boolean" +} - added
Input schema / properties / posts / items / properties / instagramConfigs / items / properties / userTagsAdded value: +{ + "description": "Public Instagram accounts tagged in the media, up to 20. Works on a single image, a single video (published as a Reel) or a single story; a carousel or several stories with tags is refused with 400. On a feed image every tag needs x and y; on a story they are optional, and on a video they are ignored because the person is tagged on the video as a whole. A leading @ is stripped and a repeated username keeps its first entry. If Instagram refuses a tag because the account is private or does not exist, the post goes out without its tags and instagramUntaggedUsernames in get_post lists the refused usernames", + "items": { + "additionalProperties": false, + "properties": { + "username": { + "description": "The public Instagram username to tag", + "pattern": "^@?[A-Za-z0-9._]{1,30}$", + "type": "string" + }, + "x": { + "description": "Horizontal position of the tag on the image, from 0 (left edge) to 1 (right edge)", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y": { + "description": "Vertical position of the tag on the image, from 0 (top edge) to 1 (bottom edge)", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "username" + ], + "type": "object" + }, + "maxItems": 20, + "type": "array" +} - changed
Input schema / properties / posts / items / properties / mediaAltTexts / descriptionPrevious value: -"Alt text per image, in the same order as mediaUrls (max 1000 characters each; use \"\" to skip an image). Sent to X, Bluesky, Mastodon, LinkedIn, Facebook, Instagram and Threads; Pinterest uses the first one (cut to 500). TikTok, YouTube, Google Business Profile and videos ignore it"New value: +"Alt text per image, in the same order as mediaUrls (max 1000 characters each; use \"\" to skip an image). Sent to X, Bluesky, Mastodon, Tumblr, LinkedIn, Facebook, Instagram and Threads; Pinterest uses the first one (cut to 500). TikTok, YouTube, Google Business Profile and videos ignore it" - changed
Input schema / properties / posts / items / properties / platformThumbnails / descriptionPrevious value: -"A different thumbnail for one platform of a VIDEO post, one entry per platform. A platform without an entry uses the post-level thumbnailUrl and thumbnailTimestampMs. YOUTUBE, FACEBOOK and LINKEDIN take an image (thumbnailUrl); INSTAGRAM and PINTEREST take an image or a frame (thumbnailTimestampMs), the image winning when both are sent; TIKTOK takes only a frame. Posts that are not videos, Facebook and Instagram stories, a second entry for one platform and an entry the platform cannot use are refused with 400. On an update, sending the array replaces every override and omitting it keeps the stored ones"New value: +"A different thumbnail for one platform of a VIDEO post, one entry per platform. A platform without an entry uses the post-level thumbnailUrl and thumbnailTimestampMs. YOUTUBE, FACEBOOK, LINKEDIN and TELEGRAM take an image (thumbnailUrl); INSTAGRAM and PINTEREST take an image or a frame (thumbnailTimestampMs), the image winning when both are sent; TIKTOK takes only a frame. Posts that are not videos, Facebook and Instagram stories, a second entry for one platform and an entry the platform cannot use are refused with 400. On an update, sending the array replaces every override and omitting it keeps the stored ones" - changed
Input schema / properties / posts / items / properties / platformThumbnails / items / properties / platform / enumPrevious value: -[ - "YOUTUBE", - "FACEBOOK", - "LINKEDIN", - "INSTAGRAM", - "PINTEREST", - "TIKTOK" -]New value: +[ + "YOUTUBE", + "FACEBOOK", + "LINKEDIN", + "TELEGRAM", + "INSTAGRAM", + "PINTEREST", + "TIKTOK" +] - added
Input schema / properties / posts / items / properties / threadRepliesAdded value: +{ + "description": "Turns the post into a thread: the post opens it and each text is published as a reply to the one before, from the same account, one entry per platform. Available on TWITTER (280 characters per reply, or the account's own limit on X Premium), THREADS (500), BLUESKY (300) and MASTODON (500, or the instance's limit), up to 25 replies. A platform the post does not go to, an empty or too long reply, more than 25 replies, a second entry for one platform and a platform that also has a first comment are refused with 400. An entry with an empty texts array removes the thread. Replies start about 10 seconds after the platform publishes, 2 seconds apart. A failed run is retried up to 3 times and resumes after the last reply that went out; on X it is not retried, and a lifetime-deal account pays for each reply like any X post. A thread that fails never fails the post: read threadStatus, threadReplyIds and threadError on the platform in get_post. On an update, sending the array replaces every thread and omitting it keeps the stored ones", + "items": { + "additionalProperties": false, + "properties": { + "platform": { + "enum": [ + "TWITTER", + "THREADS", + "BLUESKY", + "MASTODON" + ], + "type": "string" + }, + "texts": { + "description": "The replies in order, each trimmed. The limit per reply depends on the platform, see threadReplies", + "items": { + "type": "string" + }, + "maxItems": 25, + "type": "array" + } + }, + "required": [ + "platform", + "texts" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / posts / items / properties / tumblrConfigsAdded value: +{ + "description": "Tumblr config for this item only, such as its own tags; replaces the batch-level tumblrConfigs", + "items": { + "additionalProperties": false, + "properties": { + "connectionId": { + "description": "Tumblr blog account id from list_accounts", + "type": "string" + }, + "sourceUrl": { + "description": "Shown as the source link of the post", + "maxLength": 2048, + "type": "string" + }, + "tags": { + "description": "Tumblr tags, without commas, up to 30. A leading # is stripped and duplicates are dropped, ignoring case", + "items": { + "type": "string" + }, + "maxItems": 30, + "type": "array" + }, + "title": { + "description": "Shown as a heading above the media and the text", + "maxLength": 4096, + "type": "string" + } + }, + "required": [ + "connectionId" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / posts / items / properties / youtubeConfigs / items / properties / aiGeneratedAdded value: +{ + "description": "Disclose altered or synthetic content, such as an AI voice, an AI avatar or realistic footage that was generated or edited. YouTube shows its \"Altered or synthetic content\" label on the video. Omit it or send false for no label", + "type": "boolean" +} - added
Input schema / properties / telegramConnectionIdsAdded value: +{ + "description": "Telegram channels and groups to post to, by the account id from list_accounts. TELEGRAM takes text up to 4096 characters, up to 10 images (JPEG, PNG or WebP, 10 MB each) or one MP4 or MOV video (50 MB); a caption over 1024 characters goes out as its own message after the media", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / tumblrConfigsAdded value: +{ + "description": "Tumblr per-blog config: tags, a title and a source link. connectionId must match an entry in tumblrConnectionIds", + "items": { + "$ref": "#/properties/posts/items/properties/tumblrConfigs/items" + }, + "type": "array" +} - added
Input schema / properties / tumblrConnectionIdsAdded value: +{ + "description": "Tumblr blog account ids from list_accounts to post to", + "items": { + "type": "string" + }, + "type": "array" +}
- Added
check_account - Added
check_rss_feed - Added
create_connect_link - Changed
create_post24 fields changed- added
Input schema / properties / accountIdsAdded value: +{ + "description": "Account ids (or Facebook pageIds) from list_accounts to post to. AdaptlyPost adds each account's platform to platforms and its id to the matching connection-id array, so you can send these instead of platforms and the per-platform arrays, or alongside them. An id not connected to the workspace fails with 400", + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" +} - changed
Input schema / properties / contentType / descriptionPrevious value: -"Content type: TEXT, IMAGE, VIDEO, CAROUSEL, or DOCUMENT. Must match mediaUrls. CAROUSEL takes 2 or more items in mediaUrls, up to 4 on TWITTER, BLUESKY and MASTODON, 5 on PINTEREST, 10 on INSTAGRAM, FACEBOOK and THREADS, 20 on LINKEDIN and 35 on TIKTOK (JPEG or WebP photos only). INSTAGRAM and THREADS accept images and videos in the same carousel; every other platform takes images only, and YOUTUBE has no carousel. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters. DOCUMENT publishes one PDF, PPT, PPTX, DOC or DOCX file (max 100 MB, 300 pages) as a LinkedIn document post and is LinkedIn only: put exactly that one file in mediaUrls, target only LINKEDIN, and set the title with linkedinConfigs"New value: +"Content type: TEXT, IMAGE, VIDEO, CAROUSEL, or DOCUMENT. Must match mediaUrls. CAROUSEL takes 2 or more items in mediaUrls, up to 4 on TWITTER, BLUESKY and MASTODON, 5 on PINTEREST, 10 on INSTAGRAM, FACEBOOK, THREADS and TELEGRAM, 20 on LINKEDIN, 30 on TUMBLR and 35 on TIKTOK (JPEG or WebP photos only). INSTAGRAM and THREADS accept images and videos in the same carousel; every other platform takes images only, and YOUTUBE has no carousel. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters. TELEGRAM takes text up to 4096 characters, up to 10 images (JPEG, PNG or WebP, 10 MB each) or one MP4 or MOV video (50 MB); a caption over 1024 characters goes out as its own message after the media. DOCUMENT publishes one PDF, PPT, PPTX, DOC or DOCX file (max 100 MB, 300 pages) as a LinkedIn document post and is LinkedIn only: put exactly that one file in mediaUrls, target only LINKEDIN, and set the title with linkedinConfigs" - changed
Input schema / properties / facebookConfigs / descriptionPrevious value: -"Facebook per-page config: post type, shareToStory, video title and text background. pageId must match an entry in pageIds"New value: +"Facebook per-page config: post type, shareToStory, video title, text background, and a grid or link carousel for several images. pageId must match an entry in pageIds" - added
Input schema / properties / facebookConfigs / items / properties / carouselCardsAdded value: +{ + "description": "One card per image, in the same order as the media, used when imageLayout is CAROUSEL. Facebook only shows your image, title and description on a card whose link points to a website the Page owns; for any other link the post fails with the error Facebook returns", + "items": { + "additionalProperties": false, + "properties": { + "description": { + "description": "The line under the headline, such as a price or the domain. Without it Facebook uses the linked page", + "maxLength": 200, + "type": "string" + }, + "link": { + "description": "The http or https URL the card opens", + "maxLength": 2048, + "type": "string" + }, + "title": { + "description": "The card's headline. Without it Facebook uses the linked page's title", + "maxLength": 100, + "type": "string" + } + }, + "required": [ + "link" + ], + "type": "object" + }, + "maxItems": 5, + "type": "array" +} - added
Input schema / properties / facebookConfigs / items / properties / imageLayoutAdded value: +{ + "description": "How a post with several images shows on Facebook. GRID is a photo grid. CAROUSEL is a swipeable carousel where each image is a card with its own link, and needs 2 to 5 images, no videos, postType FEED and one carouselCards entry per image; anything else is refused with 400", + "enum": [ + "GRID", + "CAROUSEL" + ], + "type": "string" +} - changed
Input schema / properties / firstComments / descriptionPrevious value: -"A comment posted from the same account right after the post goes out on a platform, one entry per platform. Available on LINKEDIN (1250 characters), TWITTER (280, as a reply), THREADS (500, as a reply), BLUESKY (300, as a reply), MASTODON (500, as a reply) and YOUTUBE (10000). A platform the post does not go to, an empty or too long comment, a second entry for one platform, a private or made for kids YouTube video and Facebook or Instagram stories are refused with 400. The comment is posted about 10 seconds after the platform publishes (60 on YouTube) and retried up to 3 times; on X it is not retried, and a lifetime-deal account pays for it like any X post. A comment that fails never fails the post: read firstCommentStatus and firstCommentError on the platform in get_post. On an update, sending the array replaces every first comment and omitting it keeps the stored ones"New value: +"A comment posted from the same account right after the post goes out on a platform, one entry per platform. Available on LINKEDIN (1250 characters), TWITTER (280, as a reply), THREADS (500, as a reply), BLUESKY (300, as a reply), MASTODON (500, as a reply), YOUTUBE (10000), FACEBOOK (8000) and INSTAGRAM (2200). A platform the post does not go to, an empty or too long comment, a second entry for one platform, a platform that also has threadReplies, a private or made for kids YouTube video and Facebook or Instagram stories are refused with 400. The comment is posted about 10 seconds after the platform publishes (60 on YouTube) and retried up to 3 times; on X it is not retried, and a lifetime-deal account pays for it like any X post. A Facebook Page or Instagram account connected before first comments came to them must be reconnected once; until then its comment fails and firstCommentError says to reconnect. A comment that fails never fails the post: read firstCommentStatus and firstCommentError on the platform in get_post. On an update, sending the array replaces every first comment and omitting it keeps the stored ones" - changed
Input schema / properties / firstComments / items / properties / platform / enumPrevious value: -[ - "LINKEDIN", - "TWITTER", - "THREADS", - "BLUESKY", - "MASTODON", - "YOUTUBE" -]New value: +[ + "LINKEDIN", + "TWITTER", + "THREADS", + "BLUESKY", + "MASTODON", + "YOUTUBE", + "FACEBOOK", + "INSTAGRAM" +] - changed
Input schema / properties / instagramConfigs / descriptionPrevious value: -"Instagram per-connection config: post type (FEED, REEL, STORY), shareToStory, collaborators, Reel audio, and trial reels"New value: +"Instagram per-connection config: post type (FEED, REEL, STORY), shareToStory, collaborators, user tags, the AI info label, Reel audio, and trial reels" - added
Input schema / properties / instagramConfigs / items / properties / aiGeneratedAdded value: +{ + "description": "Disclose that the post was made or edited with AI. Instagram shows its \"AI info\" label on the post. Works on images, carousels, reels and stories, and a story made with shareToStory carries the label too. Omit it or send false for no label", + "type": "boolean" +} - added
Input schema / properties / instagramConfigs / items / properties / userTagsAdded value: +{ + "description": "Public Instagram accounts tagged in the media, up to 20. Works on a single image, a single video (published as a Reel) or a single story; a carousel or several stories with tags is refused with 400. On a feed image every tag needs x and y; on a story they are optional, and on a video they are ignored because the person is tagged on the video as a whole. A leading @ is stripped and a repeated username keeps its first entry. If Instagram refuses a tag because the account is private or does not exist, the post goes out without its tags and instagramUntaggedUsernames in get_post lists the refused usernames", + "items": { + "additionalProperties": false, + "properties": { + "username": { + "description": "The public Instagram username to tag", + "pattern": "^@?[A-Za-z0-9._]{1,30}$", + "type": "string" + }, + "x": { + "description": "Horizontal position of the tag on the image, from 0 (left edge) to 1 (right edge)", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y": { + "description": "Vertical position of the tag on the image, from 0 (top edge) to 1 (bottom edge)", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "username" + ], + "type": "object" + }, + "maxItems": 20, + "type": "array" +} - changed
Input schema / properties / linkedinConfigs / descriptionPrevious value: -"LinkedIn per-connection config: documentTitle names a DOCUMENT post. connectionId must match an entry in linkedinConnectionIds"New value: +"LinkedIn per-connection config: documentTitle names a DOCUMENT post, reshareOf reshares another LinkedIn post with the text as commentary. connectionId must match an entry in linkedinConnectionIds" - added
Input schema / properties / linkedinConfigs / items / properties / reshareOfAdded value: +{ + "description": "Reshare this LinkedIn post from the account, with the post text as the commentary. Takes a urn:li:share: or urn:li:ugcPost: URN, such as the platformPostId from list_post_results, or a LinkedIn post link of the form https://www.linkedin.com/feed/update/<urn>, which is also the link inside a post's Embed code. urn:li:activity: links are refused because LinkedIn cannot reshare them through its API. Media on the post is not attached on this account", + "maxLength": 500, + "type": "string" +} - changed
Input schema / properties / mediaAltTexts / descriptionPrevious value: -"Alt text per image, in the same order as mediaUrls (max 1000 characters each; use \"\" to skip an image). Sent to X, Bluesky, Mastodon, LinkedIn, Facebook, Instagram and Threads; Pinterest uses the first one (cut to 500). TikTok, YouTube, Google Business Profile and videos ignore it"New value: +"Alt text per image, in the same order as mediaUrls (max 1000 characters each; use \"\" to skip an image). Sent to X, Bluesky, Mastodon, Tumblr, LinkedIn, Facebook, Instagram and Threads; Pinterest uses the first one (cut to 500). TikTok, YouTube, Google Business Profile and videos ignore it" - changed
Input schema / properties / platformThumbnails / descriptionPrevious value: -"A different thumbnail for one platform of a VIDEO post, one entry per platform. A platform without an entry uses the post-level thumbnailUrl and thumbnailTimestampMs. YOUTUBE, FACEBOOK and LINKEDIN take an image (thumbnailUrl); INSTAGRAM and PINTEREST take an image or a frame (thumbnailTimestampMs), the image winning when both are sent; TIKTOK takes only a frame. Posts that are not videos, Facebook and Instagram stories, a second entry for one platform and an entry the platform cannot use are refused with 400. On an update, sending the array replaces every override and omitting it keeps the stored ones"New value: +"A different thumbnail for one platform of a VIDEO post, one entry per platform. A platform without an entry uses the post-level thumbnailUrl and thumbnailTimestampMs. YOUTUBE, FACEBOOK, LINKEDIN and TELEGRAM take an image (thumbnailUrl); INSTAGRAM and PINTEREST take an image or a frame (thumbnailTimestampMs), the image winning when both are sent; TIKTOK takes only a frame. Posts that are not videos, Facebook and Instagram stories, a second entry for one platform and an entry the platform cannot use are refused with 400. On an update, sending the array replaces every override and omitting it keeps the stored ones" - changed
Input schema / properties / platformThumbnails / items / properties / platform / enumPrevious value: -[ - "YOUTUBE", - "FACEBOOK", - "LINKEDIN", - "INSTAGRAM", - "PINTEREST", - "TIKTOK" -]New value: +[ + "YOUTUBE", + "FACEBOOK", + "LINKEDIN", + "TELEGRAM", + "INSTAGRAM", + "PINTEREST", + "TIKTOK" +] - changed
Input schema / properties / platforms / descriptionPrevious value: -"Target platforms (e.g. [\"LINKEDIN\", \"TWITTER\"]). Each one needs its matching connection-id array (pageIds for FACEBOOK, googleBusinessConnectionIds for GOOGLE_BUSINESS) filled with ids from list_accounts"New value: +"Target platforms (e.g. [\"LINKEDIN\", \"TWITTER\"]). Each one needs its matching connection-id array (pageIds for FACEBOOK, googleBusinessConnectionIds for GOOGLE_BUSINESS) filled with ids from list_accounts. Optional when accountIds is sent" - changed
Input schema / properties / platforms / items / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON", - "GOOGLE_BUSINESS" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS", + "TUMBLR", + "TELEGRAM" +] - added
Input schema / properties / platforms / minItemsAdded value: +1 - added
Input schema / properties / telegramConnectionIdsAdded value: +{ + "description": "Telegram channels and groups to post to, by the account id from list_accounts. TELEGRAM takes text up to 4096 characters, up to 10 images (JPEG, PNG or WebP, 10 MB each) or one MP4 or MOV video (50 MB); a caption over 1024 characters goes out as its own message after the media", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / threadRepliesAdded value: +{ + "description": "Turns the post into a thread: the post opens it and each text is published as a reply to the one before, from the same account, one entry per platform. Available on TWITTER (280 characters per reply, or the account's own limit on X Premium), THREADS (500), BLUESKY (300) and MASTODON (500, or the instance's limit), up to 25 replies. A platform the post does not go to, an empty or too long reply, more than 25 replies, a second entry for one platform and a platform that also has a first comment are refused with 400. An entry with an empty texts array removes the thread. Replies start about 10 seconds after the platform publishes, 2 seconds apart. A failed run is retried up to 3 times and resumes after the last reply that went out; on X it is not retried, and a lifetime-deal account pays for each reply like any X post. A thread that fails never fails the post: read threadStatus, threadReplyIds and threadError on the platform in get_post. On an update, sending the array replaces every thread and omitting it keeps the stored ones", + "items": { + "additionalProperties": false, + "properties": { + "platform": { + "enum": [ + "TWITTER", + "THREADS", + "BLUESKY", + "MASTODON" + ], + "type": "string" + }, + "texts": { + "description": "The replies in order, each trimmed. The limit per reply depends on the platform, see threadReplies", + "items": { + "type": "string" + }, + "maxItems": 25, + "type": "array" + } + }, + "required": [ + "platform", + "texts" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / tumblrConfigsAdded value: +{ + "description": "Tumblr per-blog config: tags, a title and a source link. connectionId must match an entry in tumblrConnectionIds", + "items": { + "additionalProperties": false, + "properties": { + "connectionId": { + "description": "Tumblr blog account id from list_accounts", + "type": "string" + }, + "sourceUrl": { + "description": "Shown as the source link of the post", + "maxLength": 2048, + "type": "string" + }, + "tags": { + "description": "Tumblr tags, without commas, up to 30. A leading # is stripped and duplicates are dropped, ignoring case", + "items": { + "type": "string" + }, + "maxItems": 30, + "type": "array" + }, + "title": { + "description": "Shown as a heading above the media and the text", + "maxLength": 4096, + "type": "string" + } + }, + "required": [ + "connectionId" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / tumblrConnectionIdsAdded value: +{ + "description": "Tumblr blog account ids from list_accounts to post to", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / youtubeConfigs / items / properties / aiGeneratedAdded value: +{ + "description": "Disclose altered or synthetic content, such as an AI voice, an AI avatar or realistic footage that was generated or edited. YouTube shows its \"Altered or synthetic content\" label on the video. Omit it or send false for no label", + "type": "boolean" +} - changed
Input schema / requiredPrevious value: -[ - "platforms", - "contentType" -]New value: +[ + "contentType" +]
- Added
create_rss_feed - Added
create_webhook - Added
delete_rss_feed - Added
delete_webhook - Changed
generate_caption1 field changed- changed
Input schema / properties / platform / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON", - "GOOGLE_BUSINESS" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS", + "TUMBLR" +]
- Changed
get_analytics_overview3 fields changed- added
Input schema / properties / connectionIdsAdded value: +{ + "description": "Restrict to these accounts, by the account id from list_accounts; omit for every account", + "items": { + "type": "string" + }, + "type": "array" +} - changed
Input schema / properties / platforms / descriptionPrevious value: -"Restrict to these platforms; omit for every platform with analytics. MASTODON and TELEGRAM have no analytics and are ignored. GOOGLE_BUSINESS reports location impressions only, with no per-post numbers"New value: +"Restrict to these platforms; omit for every platform with analytics. MASTODON, TELEGRAM and TUMBLR have no analytics and are ignored. GOOGLE_BUSINESS reports location impressions only, with no per-post numbers" - changed
Input schema / properties / platforms / items / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON", - "GOOGLE_BUSINESS", - "TELEGRAM" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS", + "TUMBLR", + "TELEGRAM" +]
- Changed
get_analytics_timeseries3 fields changed- added
Input schema / properties / connectionIdsAdded value: +{ + "description": "Restrict to these accounts, by the account id from list_accounts; omit for every account", + "items": { + "type": "string" + }, + "type": "array" +} - changed
Input schema / properties / platforms / descriptionPrevious value: -"Restrict to these platforms; omit for every platform with analytics. MASTODON and TELEGRAM have no analytics and are ignored. GOOGLE_BUSINESS reports location impressions only, with no per-post numbers"New value: +"Restrict to these platforms; omit for every platform with analytics. MASTODON, TELEGRAM and TUMBLR have no analytics and are ignored. GOOGLE_BUSINESS reports location impressions only, with no per-post numbers" - changed
Input schema / properties / platforms / items / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON", - "GOOGLE_BUSINESS", - "TELEGRAM" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS", + "TUMBLR", + "TELEGRAM" +]
- Added
get_me - Changed
get_platform_breakdown1 field changed- added
Input schema / properties / connectionIdsAdded value: +{ + "description": "Restrict to these accounts, by the account id from list_accounts; omit for every account", + "items": { + "type": "string" + }, + "type": "array" +}
- Changed
get_post1 field changed- changed
Output schema / properties / result / descriptionPrevious value: -"The full post record: id, status, contentType, text, scheduledAt, timezone, mediaUrls, createdAt, updatedAt, recurringPostId and occurrenceAt (set when the post is an occurrence of a recurring post; occurrenceAt is its slot in the series and stays the same when the post is rescheduled), and platforms (one entry per target with id, platform, connectionId or pageId, status, errorMessage, platformPostId, postUrl once published, mediaUrls, previewUrls, and the per-platform settings: firstComment with firstCommentStatus PENDING, PUBLISHED or FAILED, firstCommentError and firstCommentPublishedAt; thumbnailUrl and thumbnailTimestampMs overrides; mediaAspectRatio and mediaAspectRatioFit; instagramCollaborators, instagramUsername and instagramAudioId, instagramAudioTitle, instagramAudioArtist, instagramAudioVolume, instagramVideoVolume; facebookTextFormatPresetId; twitterKeepLinks; googleBusinessTopicType, googleBusinessCallToActionType, googleBusinessCallToActionUrl, googleBusinessEventTitle, googleBusinessEventStart, googleBusinessEventEnd and googleBusinessOffer fields). postUrl links to the published post on every platform; Instagram and Facebook stories expire after 24 hours, so for them it links to the profile or page. A shareToStory story is its own entry with postType STORY. Posts created in the AdaptlyPost app can also target TELEGRAM, which this server cannot post to. previewUrls holds one permanent preview image per media item, a still frame for videos; after publishing, mediaUrls may become platform CDN links that expire within days, so show previewUrls instead."New value: +"The full post record: id, status, contentType, text, scheduledAt, timezone, mediaUrls, createdAt, updatedAt, recurringPostId and occurrenceAt (set when the post is an occurrence of a recurring post; occurrenceAt is its slot in the series and stays the same when the post is rescheduled), and platforms (one entry per target with id, platform, connectionId or pageId, status, errorMessage, platformPostId, postUrl once published, mediaUrls, previewUrls, and the per-platform settings: firstComment with firstCommentStatus PENDING, PUBLISHED or FAILED, firstCommentError and firstCommentPublishedAt; threadReplies with threadStatus, threadReplyIds, threadError and threadPublishedAt; thumbnailUrl and thumbnailTimestampMs overrides; mediaAspectRatio and mediaAspectRatioFit; instagramCollaborators, instagramUserTags, instagramUntaggedUsernames (tags Instagram refused), instagramAiGenerated, instagramUsername and instagramAudioId, instagramAudioTitle, instagramAudioArtist, instagramAudioVolume, instagramVideoVolume; facebookTextFormatPresetId, facebookImageLayout and facebookCarouselCards; youtubeAiGenerated; linkedinDocumentTitle and linkedinReshareOf; twitterKeepLinks; tumblrTags, tumblrTitle and tumblrSourceUrl; googleBusinessTopicType, googleBusinessCallToActionType, googleBusinessCallToActionUrl, googleBusinessEventTitle, googleBusinessEventStart, googleBusinessEventEnd and googleBusinessOffer fields). postUrl links to the published post on every platform; Instagram and Facebook stories expire after 24 hours, so for them it links to the profile or page. A shareToStory story is its own entry with postType STORY. previewUrls holds one permanent preview image per media item, a still frame for videos; after publishing, mediaUrls may become platform CDN links that expire within days, so show previewUrls instead."
- Added
get_rss_feed - Added
get_webhook - Added
list_discovered_posts - Changed
list_post_analytics4 fields changed- added
Input schema / properties / connectionIdsAdded value: +{ + "description": "Restrict to these accounts, by the account id from list_accounts; omit for every account", + "items": { + "type": "string" + }, + "type": "array" +} - changed
Input schema / properties / platforms / descriptionPrevious value: -"Restrict to these platforms; omit for every platform with analytics. MASTODON and TELEGRAM have no analytics and are ignored. GOOGLE_BUSINESS reports location impressions only, with no per-post numbers"New value: +"Restrict to these platforms; omit for every platform with analytics. MASTODON, TELEGRAM and TUMBLR have no analytics and are ignored. GOOGLE_BUSINESS reports location impressions only, with no per-post numbers" - changed
Input schema / properties / platforms / items / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON", - "GOOGLE_BUSINESS", - "TELEGRAM" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS", + "TUMBLR", + "TELEGRAM" +] - changed
Output schema / properties / result / descriptionPrevious value: -"An object with posts (each { id, postId, postPlatformId, platform, publishedAt, title, thumbnailUrl, permalink, accountName, metrics }), total, page, limit, and hasMore."New value: +"An object with posts (each { id, postId, postPlatformId, platform, publishedAt, title, thumbnailUrl, permalink, connectionId, accountName, metrics }), total, page, limit, and hasMore."
- Changed
list_posts2 fields changed- changed
Input schema / properties / platforms / descriptionPrevious value: -"Filter to posts targeting any of these platforms. TELEGRAM matches posts created in the AdaptlyPost app"New value: +"Filter to posts targeting any of these platforms" - changed
Input schema / properties / platforms / items / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON", - "GOOGLE_BUSINESS", - "TELEGRAM" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS", + "TUMBLR", + "TELEGRAM" +]
- Added
list_rss_feed_items - Added
list_rss_feeds - Added
list_top_posts - Added
list_webhooks - Added
pause_rss_feed - Added
preview_rss_feed - Changed
refine_caption1 field changed- changed
Input schema / properties / platform / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON", - "GOOGLE_BUSINESS" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS", + "TUMBLR" +]
- Added
remove_account - Added
resume_rss_feed - Added
revoke_connect_link - Added
test_webhook - Changed
update_post20 fields changed- changed
Input schema / properties / contentType / descriptionPrevious value: -"New content type; must match the media on the post. CAROUSEL takes 2 or more items in mediaUrls, up to 4 on TWITTER, BLUESKY and MASTODON, 5 on PINTEREST, 10 on INSTAGRAM, FACEBOOK and THREADS, 20 on LINKEDIN and 35 on TIKTOK (JPEG or WebP photos only). INSTAGRAM and THREADS accept images and videos in the same carousel; every other platform takes images only, and YOUTUBE has no carousel. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters. DOCUMENT publishes one PDF, PPT, PPTX, DOC or DOCX file (max 100 MB, 300 pages) as a LinkedIn document post and is LinkedIn only: put exactly that one file in mediaUrls, target only LINKEDIN, and set the title with linkedinConfigs"New value: +"New content type; must match the media on the post. CAROUSEL takes 2 or more items in mediaUrls, up to 4 on TWITTER, BLUESKY and MASTODON, 5 on PINTEREST, 10 on INSTAGRAM, FACEBOOK, THREADS and TELEGRAM, 20 on LINKEDIN, 30 on TUMBLR and 35 on TIKTOK (JPEG or WebP photos only). INSTAGRAM and THREADS accept images and videos in the same carousel; every other platform takes images only, and YOUTUBE has no carousel. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters. DOCUMENT publishes one PDF, PPT, PPTX, DOC or DOCX file (max 100 MB, 300 pages) as a LinkedIn document post and is LinkedIn only: put exactly that one file in mediaUrls, target only LINKEDIN, and set the title with linkedinConfigs" - changed
Input schema / properties / facebookConfigs / descriptionPrevious value: -"Facebook per-page config: post type, shareToStory, video title and text background. pageId must match an entry in pageIds"New value: +"Facebook per-page config: post type, shareToStory, video title, text background, and a grid or link carousel for several images. pageId must match an entry in pageIds" - added
Input schema / properties / facebookConfigs / items / properties / carouselCardsAdded value: +{ + "description": "One card per image, in the same order as the media, used when imageLayout is CAROUSEL. Facebook only shows your image, title and description on a card whose link points to a website the Page owns; for any other link the post fails with the error Facebook returns", + "items": { + "additionalProperties": false, + "properties": { + "description": { + "description": "The line under the headline, such as a price or the domain. Without it Facebook uses the linked page", + "maxLength": 200, + "type": "string" + }, + "link": { + "description": "The http or https URL the card opens", + "maxLength": 2048, + "type": "string" + }, + "title": { + "description": "The card's headline. Without it Facebook uses the linked page's title", + "maxLength": 100, + "type": "string" + } + }, + "required": [ + "link" + ], + "type": "object" + }, + "maxItems": 5, + "type": "array" +} - added
Input schema / properties / facebookConfigs / items / properties / imageLayoutAdded value: +{ + "description": "How a post with several images shows on Facebook. GRID is a photo grid. CAROUSEL is a swipeable carousel where each image is a card with its own link, and needs 2 to 5 images, no videos, postType FEED and one carouselCards entry per image; anything else is refused with 400", + "enum": [ + "GRID", + "CAROUSEL" + ], + "type": "string" +} - changed
Input schema / properties / firstComments / descriptionPrevious value: -"A comment posted from the same account right after the post goes out on a platform, one entry per platform. Available on LINKEDIN (1250 characters), TWITTER (280, as a reply), THREADS (500, as a reply), BLUESKY (300, as a reply), MASTODON (500, as a reply) and YOUTUBE (10000). A platform the post does not go to, an empty or too long comment, a second entry for one platform, a private or made for kids YouTube video and Facebook or Instagram stories are refused with 400. The comment is posted about 10 seconds after the platform publishes (60 on YouTube) and retried up to 3 times; on X it is not retried, and a lifetime-deal account pays for it like any X post. A comment that fails never fails the post: read firstCommentStatus and firstCommentError on the platform in get_post. On an update, sending the array replaces every first comment and omitting it keeps the stored ones"New value: +"A comment posted from the same account right after the post goes out on a platform, one entry per platform. Available on LINKEDIN (1250 characters), TWITTER (280, as a reply), THREADS (500, as a reply), BLUESKY (300, as a reply), MASTODON (500, as a reply), YOUTUBE (10000), FACEBOOK (8000) and INSTAGRAM (2200). A platform the post does not go to, an empty or too long comment, a second entry for one platform, a platform that also has threadReplies, a private or made for kids YouTube video and Facebook or Instagram stories are refused with 400. The comment is posted about 10 seconds after the platform publishes (60 on YouTube) and retried up to 3 times; on X it is not retried, and a lifetime-deal account pays for it like any X post. A Facebook Page or Instagram account connected before first comments came to them must be reconnected once; until then its comment fails and firstCommentError says to reconnect. A comment that fails never fails the post: read firstCommentStatus and firstCommentError on the platform in get_post. On an update, sending the array replaces every first comment and omitting it keeps the stored ones" - changed
Input schema / properties / firstComments / items / properties / platform / enumPrevious value: -[ - "LINKEDIN", - "TWITTER", - "THREADS", - "BLUESKY", - "MASTODON", - "YOUTUBE" -]New value: +[ + "LINKEDIN", + "TWITTER", + "THREADS", + "BLUESKY", + "MASTODON", + "YOUTUBE", + "FACEBOOK", + "INSTAGRAM" +] - changed
Input schema / properties / instagramConfigs / descriptionPrevious value: -"Instagram per-connection config: post type (FEED, REEL, STORY), shareToStory, collaborators, Reel audio, and trial reels"New value: +"Instagram per-connection config: post type (FEED, REEL, STORY), shareToStory, collaborators, user tags, the AI info label, Reel audio, and trial reels" - added
Input schema / properties / instagramConfigs / items / properties / aiGeneratedAdded value: +{ + "description": "Disclose that the post was made or edited with AI. Instagram shows its \"AI info\" label on the post. Works on images, carousels, reels and stories, and a story made with shareToStory carries the label too. Omit it or send false for no label", + "type": "boolean" +} - added
Input schema / properties / instagramConfigs / items / properties / userTagsAdded value: +{ + "description": "Public Instagram accounts tagged in the media, up to 20. Works on a single image, a single video (published as a Reel) or a single story; a carousel or several stories with tags is refused with 400. On a feed image every tag needs x and y; on a story they are optional, and on a video they are ignored because the person is tagged on the video as a whole. A leading @ is stripped and a repeated username keeps its first entry. If Instagram refuses a tag because the account is private or does not exist, the post goes out without its tags and instagramUntaggedUsernames in get_post lists the refused usernames", + "items": { + "additionalProperties": false, + "properties": { + "username": { + "description": "The public Instagram username to tag", + "pattern": "^@?[A-Za-z0-9._]{1,30}$", + "type": "string" + }, + "x": { + "description": "Horizontal position of the tag on the image, from 0 (left edge) to 1 (right edge)", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y": { + "description": "Vertical position of the tag on the image, from 0 (top edge) to 1 (bottom edge)", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "username" + ], + "type": "object" + }, + "maxItems": 20, + "type": "array" +} - changed
Input schema / properties / linkedinConfigs / descriptionPrevious value: -"LinkedIn per-connection config: documentTitle names a DOCUMENT post. connectionId must match an entry in linkedinConnectionIds"New value: +"LinkedIn per-connection config: documentTitle names a DOCUMENT post, reshareOf reshares another LinkedIn post with the text as commentary. connectionId must match an entry in linkedinConnectionIds" - added
Input schema / properties / linkedinConfigs / items / properties / reshareOfAdded value: +{ + "description": "Reshare this LinkedIn post from the account, with the post text as the commentary. Takes a urn:li:share: or urn:li:ugcPost: URN, such as the platformPostId from list_post_results, or a LinkedIn post link of the form https://www.linkedin.com/feed/update/<urn>, which is also the link inside a post's Embed code. urn:li:activity: links are refused because LinkedIn cannot reshare them through its API. Media on the post is not attached on this account", + "maxLength": 500, + "type": "string" +} - changed
Input schema / properties / mediaAltTexts / descriptionPrevious value: -"Alt text per image, in the same order as mediaUrls (max 1000 characters each; use \"\" to skip an image). Sent to X, Bluesky, Mastodon, LinkedIn, Facebook, Instagram and Threads; Pinterest uses the first one (cut to 500). TikTok, YouTube, Google Business Profile and videos ignore it. Applied only when platforms is also sent"New value: +"Alt text per image, in the same order as mediaUrls (max 1000 characters each; use \"\" to skip an image). Sent to X, Bluesky, Mastodon, Tumblr, LinkedIn, Facebook, Instagram and Threads; Pinterest uses the first one (cut to 500). TikTok, YouTube, Google Business Profile and videos ignore it. Applied only when platforms is also sent" - changed
Input schema / properties / platformThumbnails / descriptionPrevious value: -"A different thumbnail for one platform of a VIDEO post, one entry per platform. A platform without an entry uses the post-level thumbnailUrl and thumbnailTimestampMs. YOUTUBE, FACEBOOK and LINKEDIN take an image (thumbnailUrl); INSTAGRAM and PINTEREST take an image or a frame (thumbnailTimestampMs), the image winning when both are sent; TIKTOK takes only a frame. Posts that are not videos, Facebook and Instagram stories, a second entry for one platform and an entry the platform cannot use are refused with 400. On an update, sending the array replaces every override and omitting it keeps the stored ones"New value: +"A different thumbnail for one platform of a VIDEO post, one entry per platform. A platform without an entry uses the post-level thumbnailUrl and thumbnailTimestampMs. YOUTUBE, FACEBOOK, LINKEDIN and TELEGRAM take an image (thumbnailUrl); INSTAGRAM and PINTEREST take an image or a frame (thumbnailTimestampMs), the image winning when both are sent; TIKTOK takes only a frame. Posts that are not videos, Facebook and Instagram stories, a second entry for one platform and an entry the platform cannot use are refused with 400. On an update, sending the array replaces every override and omitting it keeps the stored ones" - changed
Input schema / properties / platformThumbnails / items / properties / platform / enumPrevious value: -[ - "YOUTUBE", - "FACEBOOK", - "LINKEDIN", - "INSTAGRAM", - "PINTEREST", - "TIKTOK" -]New value: +[ + "YOUTUBE", + "FACEBOOK", + "LINKEDIN", + "TELEGRAM", + "INSTAGRAM", + "PINTEREST", + "TIKTOK" +] - changed
Input schema / properties / platforms / items / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON", - "GOOGLE_BUSINESS" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS", + "TUMBLR", + "TELEGRAM" +] - added
Input schema / properties / telegramConnectionIdsAdded value: +{ + "description": "Telegram channels and groups to post to, by the account id from list_accounts. TELEGRAM takes text up to 4096 characters, up to 10 images (JPEG, PNG or WebP, 10 MB each) or one MP4 or MOV video (50 MB); a caption over 1024 characters goes out as its own message after the media", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / threadRepliesAdded value: +{ + "description": "Turns the post into a thread: the post opens it and each text is published as a reply to the one before, from the same account, one entry per platform. Available on TWITTER (280 characters per reply, or the account's own limit on X Premium), THREADS (500), BLUESKY (300) and MASTODON (500, or the instance's limit), up to 25 replies. A platform the post does not go to, an empty or too long reply, more than 25 replies, a second entry for one platform and a platform that also has a first comment are refused with 400. An entry with an empty texts array removes the thread. Replies start about 10 seconds after the platform publishes, 2 seconds apart. A failed run is retried up to 3 times and resumes after the last reply that went out; on X it is not retried, and a lifetime-deal account pays for each reply like any X post. A thread that fails never fails the post: read threadStatus, threadReplyIds and threadError on the platform in get_post. On an update, sending the array replaces every thread and omitting it keeps the stored ones", + "items": { + "additionalProperties": false, + "properties": { + "platform": { + "enum": [ + "TWITTER", + "THREADS", + "BLUESKY", + "MASTODON" + ], + "type": "string" + }, + "texts": { + "description": "The replies in order, each trimmed. The limit per reply depends on the platform, see threadReplies", + "items": { + "type": "string" + }, + "maxItems": 25, + "type": "array" + } + }, + "required": [ + "platform", + "texts" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / tumblrConfigsAdded value: +{ + "description": "Tumblr per-blog config: tags, a title and a source link. connectionId must match an entry in tumblrConnectionIds", + "items": { + "additionalProperties": false, + "properties": { + "connectionId": { + "description": "Tumblr blog account id from list_accounts", + "type": "string" + }, + "sourceUrl": { + "description": "Shown as the source link of the post", + "maxLength": 2048, + "type": "string" + }, + "tags": { + "description": "Tumblr tags, without commas, up to 30. A leading # is stripped and duplicates are dropped, ignoring case", + "items": { + "type": "string" + }, + "maxItems": 30, + "type": "array" + }, + "title": { + "description": "Shown as a heading above the media and the text", + "maxLength": 4096, + "type": "string" + } + }, + "required": [ + "connectionId" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / tumblrConnectionIdsAdded value: +{ + "description": "Tumblr blog account ids from list_accounts to post to", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / youtubeConfigs / items / properties / aiGeneratedAdded value: +{ + "description": "Disclose altered or synthetic content, such as an AI voice, an AI avatar or realistic footage that was generated or edited. YouTube shows its \"Altered or synthetic content\" label on the video. Omit it or send false for no label", + "type": "boolean" +}
- Added
update_rss_feed - Added
update_webhook - Added
validate_bulk_posts - Added
validate_post
1 tool update
- Changed
upload_media2 fields changed- added
Input schema / properties / attachmentsAdded value: +{ + "description": "Files the user attached in the ChatGPT conversation: images, videos or documents, up to 250 MB each. ChatGPT fills in each file reference; put every attached file the user wants to post here", + "items": { + "additionalProperties": true, + "properties": { + "download_url": { + "description": "Temporary download URL of the attached file", + "type": "string" + }, + "file_id": { + "description": "ChatGPT file id of the attached file", + "type": "string" + }, + "file_name": { + "description": "Name of the attached file, with its extension", + "type": [ + "string", + "null" + ] + }, + "mime_type": { + "description": "MIME type of the attached file", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "download_url", + "file_id" + ], + "type": "object" + }, + "type": "array" +} - changed
Input schema / properties / files / descriptionPrevious value: -"Direct file uploads as base64, 30 MB decoded per call in total. Use this when the user attaches/pastes an image, video or document in the conversation"New value: +"Direct file uploads as base64, 30 MB decoded per call in total. Use this for small media attached in apps other than ChatGPT; in ChatGPT use attachments"
2 tool updates
- Changed
create_post2 fields changed- changed
Input schema / properties / recurrence / descriptionPrevious value: -"Repeat the post on a schedule. Needs a future scheduledAt, which becomes the first post and sets the time of day in timezone. Cannot be combined with saveAsDraft or TIKTOK. Missed slots, for example while paused, are skipped and never published late. X and LinkedIn reject identical text, so use spintax such as {Hi|Hello} to vary each post. Manage the series with list_recurring_posts, pause_recurring_post, resume_recurring_post and delete_recurring_post"New value: +"Repeat the post on a schedule the user asked for, and confirm that schedule with them first. Needs a future scheduledAt, which becomes the first post and sets the time of day in timezone. Cannot be combined with saveAsDraft or TIKTOK. Missed slots, for example while paused, are skipped and never published late. The user can pause or stop the series at any time with pause_recurring_post or delete_recurring_post; list_recurring_posts shows it" - changed
Input schema / properties / recurrence / properties / maxOccurrences / descriptionPrevious value: -"Total number of posts the series publishes, 2 to 365. Cannot be combined with endsOn; omit both to repeat until paused or deleted"New value: +"Total number of posts the series publishes, 2 to 365. Cannot be combined with endsOn; omit both to repeat until the user pauses or deletes the series"
- Changed
generate_image1 field changed- changed
Input schema / properties / referenceImages / descriptionPrevious value: -"Up to 5 public image URLs that steer the style or subject of the result"New value: +"Up to 5 image URLs the user provided, such as publicUrl values from upload_media, to guide the style or subject"
4 tool updates
- Changed
bulk_schedule_posts4 fields changed- changed
Input schema / properties / pinterestConfigs / descriptionPrevious value: -"Pinterest per-connection config: the board to pin to, a pin title and a destination link. Get boardId from list_pinterest_boards for that connectionId; a board belongs to one Pinterest account. Without boardId the pin goes to a board named AdaptlyPost"New value: +"Pinterest per-connection config: the board to pin to, a pin title and a destination link. Get boardId from list_pinterest_boards for that connectionId, or pass the board name as boardName instead (not both); a board belongs to one Pinterest account. A boardName that matches no board or several fails with 400. Without either the pin goes to a board named AdaptlyPost" - changed
Input schema / properties / posts / items / properties / pinterestConfigs / descriptionPrevious value: -"Pinterest config for this item only, such as its own title or link; replaces the batch-level pinterestConfigs"New value: +"Pinterest config for this item only, such as its own board, title or link; replaces the batch-level pinterestConfigs" - changed
Input schema / properties / posts / items / properties / pinterestConfigs / items / properties / boardId / descriptionPrevious value: -"Board id from list_pinterest_boards. Leave out to pin to a public board named AdaptlyPost, created on the account the first time it is needed"New value: +"Board id from list_pinterest_boards. Leave out boardId and boardName to pin to a public board named AdaptlyPost, created on the account the first time it is needed" - added
Input schema / properties / posts / items / properties / pinterestConfigs / items / properties / boardNameAdded value: +{ + "description": "The board's name, instead of boardId; never send both. Matched against this account's boards, exact first, then case-insensitive. A name no board has, or one several boards share, fails with 400 and never falls back to another board", + "maxLength": 180, + "minLength": 1, + "type": "string" +}
- Changed
create_post3 fields changed- changed
Input schema / properties / pinterestConfigs / descriptionPrevious value: -"Pinterest per-connection config: the board to pin to, a pin title and a destination link. Get boardId from list_pinterest_boards for that connectionId; a board belongs to one Pinterest account. Without boardId the pin goes to a board named AdaptlyPost"New value: +"Pinterest per-connection config: the board to pin to, a pin title and a destination link. Get boardId from list_pinterest_boards for that connectionId, or pass the board name as boardName instead (not both); a board belongs to one Pinterest account. A boardName that matches no board or several fails with 400. Without either the pin goes to a board named AdaptlyPost" - changed
Input schema / properties / pinterestConfigs / items / properties / boardId / descriptionPrevious value: -"Board id from list_pinterest_boards. Leave out to pin to a public board named AdaptlyPost, created on the account the first time it is needed"New value: +"Board id from list_pinterest_boards. Leave out boardId and boardName to pin to a public board named AdaptlyPost, created on the account the first time it is needed" - added
Input schema / properties / pinterestConfigs / items / properties / boardNameAdded value: +{ + "description": "The board's name, instead of boardId; never send both. Matched against this account's boards, exact first, then case-insensitive. A name no board has, or one several boards share, fails with 400 and never falls back to another board", + "maxLength": 180, + "minLength": 1, + "type": "string" +}
- Changed
list_pinterest_boards1 field changed- changed
Output schema / properties / result / descriptionPrevious value: -"An object with boards: one { id, name, description, privacy, pinCount } per board. Pass id as pinterestConfigs[].boardId."New value: +"An object with boards: one { id, name, description, privacy, pinCount } per board. Pass id as pinterestConfigs[].boardId, or name as boardName."
- Changed
update_post3 fields changed- changed
Input schema / properties / pinterestConfigs / descriptionPrevious value: -"Pinterest per-connection config: the board to pin to, a pin title and a destination link. Get boardId from list_pinterest_boards for that connectionId; a board belongs to one Pinterest account. Without boardId the pin goes to a board named AdaptlyPost"New value: +"Pinterest per-connection config: the board to pin to, a pin title and a destination link. Get boardId from list_pinterest_boards for that connectionId, or pass the board name as boardName instead (not both); a board belongs to one Pinterest account. A boardName that matches no board or several fails with 400. Without either the pin goes to a board named AdaptlyPost" - changed
Input schema / properties / pinterestConfigs / items / properties / boardId / descriptionPrevious value: -"Board id from list_pinterest_boards. Leave out to pin to a public board named AdaptlyPost, created on the account the first time it is needed"New value: +"Board id from list_pinterest_boards. Leave out boardId and boardName to pin to a public board named AdaptlyPost, created on the account the first time it is needed" - added
Input schema / properties / pinterestConfigs / items / properties / boardNameAdded value: +{ + "description": "The board's name, instead of boardId; never send both. Matched against this account's boards, exact first, then case-insensitive. A name no board has, or one several boards share, fails with 400 and never falls back to another board", + "maxLength": 180, + "minLength": 1, + "type": "string" +}
4 tool updates
- Changed
bulk_schedule_posts3 fields changed- changed
Input schema / properties / pinterestConfigs / descriptionPrevious value: -"Pinterest per-connection config. Each entry needs connectionId + boardId; there is no API to list boards, so ask the user for the board id"New value: +"Pinterest per-connection config: the board to pin to, a pin title and a destination link. Get boardId from list_pinterest_boards for that connectionId; a board belongs to one Pinterest account. Without boardId the pin goes to a board named AdaptlyPost" - changed
Input schema / properties / posts / items / properties / pinterestConfigs / items / properties / boardId / descriptionPrevious value: -"Pinterest board ID to pin to (required)"New value: +"Board id from list_pinterest_boards. Leave out to pin to a public board named AdaptlyPost, created on the account the first time it is needed" - changed
Input schema / properties / posts / items / properties / pinterestConfigs / items / requiredPrevious value: -[ - "connectionId", - "boardId" -]New value: +[ + "connectionId" +]
- Changed
create_post3 fields changed- changed
Input schema / properties / pinterestConfigs / descriptionPrevious value: -"Pinterest per-connection config. Each entry needs connectionId + boardId; there is no API to list boards, so ask the user for the board id"New value: +"Pinterest per-connection config: the board to pin to, a pin title and a destination link. Get boardId from list_pinterest_boards for that connectionId; a board belongs to one Pinterest account. Without boardId the pin goes to a board named AdaptlyPost" - changed
Input schema / properties / pinterestConfigs / items / properties / boardId / descriptionPrevious value: -"Pinterest board ID to pin to (required)"New value: +"Board id from list_pinterest_boards. Leave out to pin to a public board named AdaptlyPost, created on the account the first time it is needed" - changed
Input schema / properties / pinterestConfigs / items / requiredPrevious value: -[ - "connectionId", - "boardId" -]New value: +[ + "connectionId" +]
- Added
list_pinterest_boards - Changed
update_post3 fields changed- changed
Input schema / properties / pinterestConfigs / descriptionPrevious value: -"Pinterest per-connection config. Each entry needs connectionId + boardId; there is no API to list boards, so ask the user for the board id"New value: +"Pinterest per-connection config: the board to pin to, a pin title and a destination link. Get boardId from list_pinterest_boards for that connectionId; a board belongs to one Pinterest account. Without boardId the pin goes to a board named AdaptlyPost" - changed
Input schema / properties / pinterestConfigs / items / properties / boardId / descriptionPrevious value: -"Pinterest board ID to pin to (required)"New value: +"Board id from list_pinterest_boards. Leave out to pin to a public board named AdaptlyPost, created on the account the first time it is needed" - changed
Input schema / properties / pinterestConfigs / items / requiredPrevious value: -[ - "connectionId", - "boardId" -]New value: +[ + "connectionId" +]
12 tool updates
- Changed
bulk_schedule_posts23 fields changed- changed
Input schema / properties / facebookConfigs / descriptionPrevious value: -"Facebook per-page config with post type and video title. pageId must match an entry in pageIds"New value: +"Facebook per-page config: post type, shareToStory, video title and text background. pageId must match an entry in pageIds" - added
Input schema / properties / googleBusinessConfigsAdded value: +{ + "description": "Google Business Profile per-location config: update, event or offer, plus a button. connectionId must match an entry in googleBusinessConnectionIds. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters", + "items": { + "$ref": "#/properties/posts/items/properties/googleBusinessConfigs/items" + }, + "type": "array" +} - added
Input schema / properties / googleBusinessConnectionIdsAdded value: +{ + "description": "Google Business Profile locations to post to, by the account id from list_accounts. A location without an entry in googleBusinessConfigs gets a STANDARD update", + "items": { + "type": "string" + }, + "type": "array" +} - changed
Input schema / properties / instagramConfigs / descriptionPrevious value: -"Instagram per-connection config to set post type (FEED, REEL, STORY) and publish a reel as a trial reel"New value: +"Instagram per-connection config: post type (FEED, REEL, STORY), shareToStory, collaborators, Reel audio, and trial reels" - changed
Input schema / properties / platforms / descriptionPrevious value: -"Target platforms shared by every item. Each needs its connection-id array (pageIds for FACEBOOK)"New value: +"Target platforms shared by every item. Each needs its connection-id array (pageIds for FACEBOOK, googleBusinessConnectionIds for GOOGLE_BUSINESS)" - changed
Input schema / properties / platforms / items / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS" +] - changed
Input schema / properties / posts / items / properties / contentType / descriptionPrevious value: -"TEXT, IMAGE, VIDEO, or CAROUSEL; must match mediaUrls. DOCUMENT posts cannot be bulk scheduled; use create_post"New value: +"TEXT, IMAGE, VIDEO, or CAROUSEL; must match mediaUrls. DOCUMENT posts cannot be bulk scheduled; use create_post. CAROUSEL takes 2 or more items in mediaUrls, up to 4 on TWITTER, BLUESKY and MASTODON, 5 on PINTEREST, 10 on INSTAGRAM, FACEBOOK and THREADS, 20 on LINKEDIN and 35 on TIKTOK (JPEG or WebP photos only). INSTAGRAM and THREADS accept images and videos in the same carousel; every other platform takes images only, and YOUTUBE has no carousel. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters" - changed
Input schema / properties / posts / items / properties / facebookConfigs / items / properties / postType / descriptionPrevious value: -"Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE or VIDEO. Any other combination is refused with 400"New value: +"Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE, VIDEO or CAROUSEL (a CAROUSEL story publishes each media item as its own story, in order). Any other combination is refused with 400" - added
Input schema / properties / posts / items / properties / facebookConfigs / items / properties / shareToStoryAdded value: +{ + "description": "Also publish the same media as a story on this page, next to the FEED or REEL post. The story shows as its own entry in platforms with postType STORY, so it succeeds, fails and retries on its own. It skips the caption, video title and text background, needs IMAGE, VIDEO or CAROUSEL, and a video must fit the story length limit (60 seconds). Ignored when postType is STORY", + "type": "boolean" +} - added
Input schema / properties / posts / items / properties / facebookConfigs / items / properties / textFormatPresetIdAdded value: +{ + "description": "Facebook's id for a colored text background (for example 106018623298955 is solid purple, 249307305544279 is a red to blue gradient). Only for contentType TEXT posts with no media and text up to 130 characters; anything else is refused with 400. Links in the text show without a preview. If Facebook refuses the background, the post goes out as plain text", + "pattern": "^\\d{1,20}$", + "type": "string" +} - added
Input schema / properties / posts / items / properties / firstCommentsAdded value: +{ + "description": "A comment posted from the same account right after the post goes out on a platform, one entry per platform. Available on LINKEDIN (1250 characters), TWITTER (280, as a reply), THREADS (500, as a reply), BLUESKY (300, as a reply), MASTODON (500, as a reply) and YOUTUBE (10000). A platform the post does not go to, an empty or too long comment, a second entry for one platform, a private or made for kids YouTube video and Facebook or Instagram stories are refused with 400. The comment is posted about 10 seconds after the platform publishes (60 on YouTube) and retried up to 3 times; on X it is not retried, and a lifetime-deal account pays for it like any X post. A comment that fails never fails the post: read firstCommentStatus and firstCommentError on the platform in get_post. On an update, sending the array replaces every first comment and omitting it keeps the stored ones", + "items": { + "additionalProperties": false, + "properties": { + "platform": { + "enum": [ + "LINKEDIN", + "TWITTER", + "THREADS", + "BLUESKY", + "MASTODON", + "YOUTUBE" + ], + "type": "string" + }, + "text": { + "description": "The comment's text, trimmed. The limit depends on the platform, see firstComments", + "maxLength": 10000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "platform", + "text" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / posts / items / properties / googleBusinessConfigsAdded value: +{ + "description": "Google Business Profile config for this item only, such as its own event or offer; replaces the batch-level googleBusinessConfigs", + "items": { + "additionalProperties": false, + "properties": { + "callToActionType": { + "description": "Button shown on the post. Every type except CALL needs callToActionUrl; CALL dials the phone number on the Business Profile", + "enum": [ + "BOOK", + "ORDER", + "SHOP", + "LEARN_MORE", + "SIGN_UP", + "CALL" + ], + "type": "string" + }, + "callToActionUrl": { + "description": "Ignored when callToActionType is CALL", + "format": "uri", + "type": "string" + }, + "connectionId": { + "description": "Google Business Profile account id from list_accounts", + "type": "string" + }, + "eventEnd": { + "$ref": "#/properties/posts/items/properties/googleBusinessConfigs/items/properties/eventStart", + "description": "YYYY-MM-DD or YYYY-MM-DDTHH:mm in the business's local time, with no offset (e.g. \"2026-10-01T21:00\")" + }, + "eventStart": { + "description": "YYYY-MM-DD or YYYY-MM-DDTHH:mm in the business's local time, with no offset (e.g. \"2026-10-01T18:00\"). Google reads event times in the location's time zone", + "pattern": "^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2})?$", + "type": "string" + }, + "eventTitle": { + "description": "Title of the event or offer", + "type": "string" + }, + "offerCouponCode": { + "description": "OFFER only: coupon code", + "type": "string" + }, + "offerRedeemUrl": { + "description": "OFFER only: where the offer is redeemed", + "format": "uri", + "type": "string" + }, + "offerTerms": { + "description": "OFFER only: terms and conditions", + "type": "string" + }, + "topicType": { + "description": "STANDARD is an update. EVENT and OFFER need eventTitle, eventStart and eventEnd", + "enum": [ + "STANDARD", + "EVENT", + "OFFER" + ], + "type": "string" + } + }, + "required": [ + "connectionId", + "topicType" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / posts / items / properties / instagramConfigs / items / properties / audioAdded value: +{ + "additionalProperties": false, + "description": "Music or an original sound from Instagram's audio library, added to the Reel when it is published. Needs contentType VIDEO and a postType other than STORY, and only works for accounts with supportsInstagramAudio: true in list_accounts (connected through Facebook). Find ids with search_instagram_audio", + "properties": { + "artist": { + "description": "Artist or creator, stored for display only", + "maxLength": 255, + "type": "string" + }, + "audioId": { + "description": "audioId from search_instagram_audio", + "maxLength": 64, + "minLength": 1, + "type": "string" + }, + "audioVolume": { + "description": "Volume of the added audio, 1 to 100. Defaults to 100", + "maximum": 100, + "minimum": 1, + "type": "integer" + }, + "title": { + "description": "Track title, stored for display only", + "maxLength": 255, + "type": "string" + }, + "videoVolume": { + "description": "Volume of the video's own sound, 1 to 100. Defaults to 100", + "maximum": 100, + "minimum": 1, + "type": "integer" + } + }, + "required": [ + "audioId" + ], + "type": "object" +} - added
Input schema / properties / posts / items / properties / instagramConfigs / items / properties / collaboratorsAdded value: +{ + "description": "Instagram usernames invited as collaborators (Instagram Collab), up to 3. A leading @ is stripped and duplicates are dropped. Works on feed images, carousels and reels; a story or a trial reel with collaborators is refused with 400. Each collaborator gets an invite in Instagram and must accept it before the post shows on their profile", + "items": { + "pattern": "^@?[A-Za-z0-9._]{1,30}$", + "type": "string" + }, + "maxItems": 3, + "type": "array" +} - changed
Input schema / properties / posts / items / properties / instagramConfigs / items / properties / postType / descriptionPrevious value: -"Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE or VIDEO. Any other combination is refused with 400"New value: +"Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE, VIDEO or CAROUSEL (a CAROUSEL story publishes each media item as its own story, in order). Any other combination is refused with 400" - added
Input schema / properties / posts / items / properties / instagramConfigs / items / properties / shareToStoryAdded value: +{ + "description": "Also publish the same media as a story on this account, next to the FEED or REEL post. The story shows as its own entry in platforms with postType STORY, so it succeeds, fails and retries on its own. It skips the caption, first comment, cover, collaborators, trial and audio, needs IMAGE, VIDEO or CAROUSEL, and a video must fit the story length limit (60 seconds). Ignored when postType is STORY", + "type": "boolean" +} - changed
Input schema / properties / posts / items / properties / mediaAltTexts / descriptionPrevious value: -"Alt text per image, in the same order as mediaUrls (max 1000 characters each; use \"\" to skip an image). Sent to X, Bluesky, Mastodon, LinkedIn, Facebook, Instagram and Threads; Pinterest uses the first one (cut to 500). TikTok, YouTube and videos ignore it"New value: +"Alt text per image, in the same order as mediaUrls (max 1000 characters each; use \"\" to skip an image). Sent to X, Bluesky, Mastodon, LinkedIn, Facebook, Instagram and Threads; Pinterest uses the first one (cut to 500). TikTok, YouTube, Google Business Profile and videos ignore it" - added
Input schema / properties / posts / items / properties / platformAspectRatiosAdded value: +{ + "description": "Reframe every image of an IMAGE or CAROUSEL post to one shape on a platform, one entry per platform. INSTAGRAM takes SQUARE, PORTRAIT or LANDSCAPE (Instagram refuses 9:16 feed and carousel images); TIKTOK takes all four. Video posts, Instagram stories and a second entry for the same platform are refused with 400. Omit a platform to keep its images as uploaded. On an update it applies to the mediaUrls sent in the same request", + "items": { + "additionalProperties": false, + "properties": { + "aspectRatio": { + "description": "SQUARE is 1:1, PORTRAIT 4:5, VERTICAL 9:16 and LANDSCAPE 1.91:1", + "enum": [ + "SQUARE", + "PORTRAIT", + "VERTICAL", + "LANDSCAPE" + ], + "type": "string" + }, + "fit": { + "description": "How an image of another shape reaches the ratio. CROP (the default) cuts it from the center; PAD keeps the whole image and fills the rest with a blurred copy of it", + "enum": [ + "CROP", + "PAD" + ], + "type": "string" + }, + "platform": { + "enum": [ + "INSTAGRAM", + "TIKTOK" + ], + "type": "string" + } + }, + "required": [ + "platform", + "aspectRatio" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / posts / items / properties / platformTexts / items / properties / text / descriptionAdded value: +"On LinkedIn, mention a company page with @[Page Name](urn:li:organization:<id>), using the page name exactly as LinkedIn shows it" - added
Input schema / properties / posts / items / properties / platformThumbnailsAdded value: +{ + "description": "A different thumbnail for one platform of a VIDEO post, one entry per platform. A platform without an entry uses the post-level thumbnailUrl and thumbnailTimestampMs. YOUTUBE, FACEBOOK and LINKEDIN take an image (thumbnailUrl); INSTAGRAM and PINTEREST take an image or a frame (thumbnailTimestampMs), the image winning when both are sent; TIKTOK takes only a frame. Posts that are not videos, Facebook and Instagram stories, a second entry for one platform and an entry the platform cannot use are refused with 400. On an update, sending the array replaces every override and omitting it keeps the stored ones", + "items": { + "additionalProperties": false, + "properties": { + "platform": { + "enum": [ + "YOUTUBE", + "FACEBOOK", + "LINKEDIN", + "INSTAGRAM", + "PINTEREST", + "TIKTOK" + ], + "type": "string" + }, + "thumbnailTimestampMs": { + "description": "The video frame (ms from the start) to use as this platform's thumbnail", + "minimum": 0, + "type": "integer" + }, + "thumbnailUrl": { + "description": "The image to use as this platform's thumbnail, an https URL or an image data URI", + "type": "string" + } + }, + "required": [ + "platform" + ], + "type": "object" + }, + "type": "array" +} - changed
Input schema / properties / posts / items / properties / text / descriptionPrevious value: -"Post text/caption"New value: +"Post text/caption. On LinkedIn, mention a company page with @[Page Name](urn:li:organization:<id>), using the page name exactly as LinkedIn shows it" - changed
Input schema / properties / posts / items / properties / thumbnailTimestampMs / descriptionPrevious value: -"Thumbnail timestamp in ms"New value: +"Video frame timestamp (ms) to use as the thumbnail, used by INSTAGRAM, PINTEREST and TIKTOK unless platformThumbnails overrides it" - changed
Input schema / properties / posts / items / properties / thumbnailUrl / descriptionPrevious value: -"Custom thumbnail image URL"New value: +"Video thumbnail as an https URL or an image data URI, used on every platform that takes one unless platformThumbnails overrides it"
- Changed
create_post26 fields changed- changed
Input schema / properties / contentType / descriptionPrevious value: -"Content type: TEXT, IMAGE, VIDEO, CAROUSEL, or DOCUMENT. Must match mediaUrls (CAROUSEL needs several). DOCUMENT publishes one PDF, PPT, PPTX, DOC or DOCX file (max 100 MB, 300 pages) as a LinkedIn document post and is LinkedIn only: put exactly that one file in mediaUrls, target only LINKEDIN, and set the title with linkedinConfigs"New value: +"Content type: TEXT, IMAGE, VIDEO, CAROUSEL, or DOCUMENT. Must match mediaUrls. CAROUSEL takes 2 or more items in mediaUrls, up to 4 on TWITTER, BLUESKY and MASTODON, 5 on PINTEREST, 10 on INSTAGRAM, FACEBOOK and THREADS, 20 on LINKEDIN and 35 on TIKTOK (JPEG or WebP photos only). INSTAGRAM and THREADS accept images and videos in the same carousel; every other platform takes images only, and YOUTUBE has no carousel. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters. DOCUMENT publishes one PDF, PPT, PPTX, DOC or DOCX file (max 100 MB, 300 pages) as a LinkedIn document post and is LinkedIn only: put exactly that one file in mediaUrls, target only LINKEDIN, and set the title with linkedinConfigs" - changed
Input schema / properties / facebookConfigs / descriptionPrevious value: -"Facebook per-page config with post type and video title. pageId must match an entry in pageIds"New value: +"Facebook per-page config: post type, shareToStory, video title and text background. pageId must match an entry in pageIds" - changed
Input schema / properties / facebookConfigs / items / properties / postType / descriptionPrevious value: -"Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE or VIDEO. Any other combination is refused with 400"New value: +"Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE, VIDEO or CAROUSEL (a CAROUSEL story publishes each media item as its own story, in order). Any other combination is refused with 400" - added
Input schema / properties / facebookConfigs / items / properties / shareToStoryAdded value: +{ + "description": "Also publish the same media as a story on this page, next to the FEED or REEL post. The story shows as its own entry in platforms with postType STORY, so it succeeds, fails and retries on its own. It skips the caption, video title and text background, needs IMAGE, VIDEO or CAROUSEL, and a video must fit the story length limit (60 seconds). Ignored when postType is STORY", + "type": "boolean" +} - added
Input schema / properties / facebookConfigs / items / properties / textFormatPresetIdAdded value: +{ + "description": "Facebook's id for a colored text background (for example 106018623298955 is solid purple, 249307305544279 is a red to blue gradient). Only for contentType TEXT posts with no media and text up to 130 characters; anything else is refused with 400. Links in the text show without a preview. If Facebook refuses the background, the post goes out as plain text", + "pattern": "^\\d{1,20}$", + "type": "string" +} - added
Input schema / properties / firstCommentsAdded value: +{ + "description": "A comment posted from the same account right after the post goes out on a platform, one entry per platform. Available on LINKEDIN (1250 characters), TWITTER (280, as a reply), THREADS (500, as a reply), BLUESKY (300, as a reply), MASTODON (500, as a reply) and YOUTUBE (10000). A platform the post does not go to, an empty or too long comment, a second entry for one platform, a private or made for kids YouTube video and Facebook or Instagram stories are refused with 400. The comment is posted about 10 seconds after the platform publishes (60 on YouTube) and retried up to 3 times; on X it is not retried, and a lifetime-deal account pays for it like any X post. A comment that fails never fails the post: read firstCommentStatus and firstCommentError on the platform in get_post. On an update, sending the array replaces every first comment and omitting it keeps the stored ones", + "items": { + "additionalProperties": false, + "properties": { + "platform": { + "enum": [ + "LINKEDIN", + "TWITTER", + "THREADS", + "BLUESKY", + "MASTODON", + "YOUTUBE" + ], + "type": "string" + }, + "text": { + "description": "The comment's text, trimmed. The limit depends on the platform, see firstComments", + "maxLength": 10000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "platform", + "text" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / googleBusinessConfigsAdded value: +{ + "description": "Google Business Profile per-location config: update, event or offer, plus a button. connectionId must match an entry in googleBusinessConnectionIds. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters", + "items": { + "additionalProperties": false, + "properties": { + "callToActionType": { + "description": "Button shown on the post. Every type except CALL needs callToActionUrl; CALL dials the phone number on the Business Profile", + "enum": [ + "BOOK", + "ORDER", + "SHOP", + "LEARN_MORE", + "SIGN_UP", + "CALL" + ], + "type": "string" + }, + "callToActionUrl": { + "description": "Ignored when callToActionType is CALL", + "format": "uri", + "type": "string" + }, + "connectionId": { + "description": "Google Business Profile account id from list_accounts", + "type": "string" + }, + "eventEnd": { + "$ref": "#/properties/googleBusinessConfigs/items/properties/eventStart", + "description": "YYYY-MM-DD or YYYY-MM-DDTHH:mm in the business's local time, with no offset (e.g. \"2026-10-01T21:00\")" + }, + "eventStart": { + "description": "YYYY-MM-DD or YYYY-MM-DDTHH:mm in the business's local time, with no offset (e.g. \"2026-10-01T18:00\"). Google reads event times in the location's time zone", + "pattern": "^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2})?$", + "type": "string" + }, + "eventTitle": { + "description": "Title of the event or offer", + "type": "string" + }, + "offerCouponCode": { + "description": "OFFER only: coupon code", + "type": "string" + }, + "offerRedeemUrl": { + "description": "OFFER only: where the offer is redeemed", + "format": "uri", + "type": "string" + }, + "offerTerms": { + "description": "OFFER only: terms and conditions", + "type": "string" + }, + "topicType": { + "description": "STANDARD is an update. EVENT and OFFER need eventTitle, eventStart and eventEnd", + "enum": [ + "STANDARD", + "EVENT", + "OFFER" + ], + "type": "string" + } + }, + "required": [ + "connectionId", + "topicType" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / googleBusinessConnectionIdsAdded value: +{ + "description": "Google Business Profile locations to post to, by the account id from list_accounts. A location without an entry in googleBusinessConfigs gets a STANDARD update", + "items": { + "type": "string" + }, + "type": "array" +} - changed
Input schema / properties / instagramConfigs / descriptionPrevious value: -"Instagram per-connection config to set post type (FEED, REEL, STORY) and publish a reel as a trial reel"New value: +"Instagram per-connection config: post type (FEED, REEL, STORY), shareToStory, collaborators, Reel audio, and trial reels" - added
Input schema / properties / instagramConfigs / items / properties / audioAdded value: +{ + "additionalProperties": false, + "description": "Music or an original sound from Instagram's audio library, added to the Reel when it is published. Needs contentType VIDEO and a postType other than STORY, and only works for accounts with supportsInstagramAudio: true in list_accounts (connected through Facebook). Find ids with search_instagram_audio", + "properties": { + "artist": { + "description": "Artist or creator, stored for display only", + "maxLength": 255, + "type": "string" + }, + "audioId": { + "description": "audioId from search_instagram_audio", + "maxLength": 64, + "minLength": 1, + "type": "string" + }, + "audioVolume": { + "description": "Volume of the added audio, 1 to 100. Defaults to 100", + "maximum": 100, + "minimum": 1, + "type": "integer" + }, + "title": { + "description": "Track title, stored for display only", + "maxLength": 255, + "type": "string" + }, + "videoVolume": { + "description": "Volume of the video's own sound, 1 to 100. Defaults to 100", + "maximum": 100, + "minimum": 1, + "type": "integer" + } + }, + "required": [ + "audioId" + ], + "type": "object" +} - added
Input schema / properties / instagramConfigs / items / properties / collaboratorsAdded value: +{ + "description": "Instagram usernames invited as collaborators (Instagram Collab), up to 3. A leading @ is stripped and duplicates are dropped. Works on feed images, carousels and reels; a story or a trial reel with collaborators is refused with 400. Each collaborator gets an invite in Instagram and must accept it before the post shows on their profile", + "items": { + "pattern": "^@?[A-Za-z0-9._]{1,30}$", + "type": "string" + }, + "maxItems": 3, + "type": "array" +} - changed
Input schema / properties / instagramConfigs / items / properties / postType / descriptionPrevious value: -"Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE or VIDEO. Any other combination is refused with 400"New value: +"Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE, VIDEO or CAROUSEL (a CAROUSEL story publishes each media item as its own story, in order). Any other combination is refused with 400" - added
Input schema / properties / instagramConfigs / items / properties / shareToStoryAdded value: +{ + "description": "Also publish the same media as a story on this account, next to the FEED or REEL post. The story shows as its own entry in platforms with postType STORY, so it succeeds, fails and retries on its own. It skips the caption, first comment, cover, collaborators, trial and audio, needs IMAGE, VIDEO or CAROUSEL, and a video must fit the story length limit (60 seconds). Ignored when postType is STORY", + "type": "boolean" +} - changed
Input schema / properties / mediaAltTexts / descriptionPrevious value: -"Alt text per image, in the same order as mediaUrls (max 1000 characters each; use \"\" to skip an image). Sent to X, Bluesky, Mastodon, LinkedIn, Facebook, Instagram and Threads; Pinterest uses the first one (cut to 500). TikTok, YouTube and videos ignore it"New value: +"Alt text per image, in the same order as mediaUrls (max 1000 characters each; use \"\" to skip an image). Sent to X, Bluesky, Mastodon, LinkedIn, Facebook, Instagram and Threads; Pinterest uses the first one (cut to 500). TikTok, YouTube, Google Business Profile and videos ignore it" - added
Input schema / properties / platformAspectRatiosAdded value: +{ + "description": "Reframe every image of an IMAGE or CAROUSEL post to one shape on a platform, one entry per platform. INSTAGRAM takes SQUARE, PORTRAIT or LANDSCAPE (Instagram refuses 9:16 feed and carousel images); TIKTOK takes all four. Video posts, Instagram stories and a second entry for the same platform are refused with 400. Omit a platform to keep its images as uploaded. On an update it applies to the mediaUrls sent in the same request", + "items": { + "additionalProperties": false, + "properties": { + "aspectRatio": { + "description": "SQUARE is 1:1, PORTRAIT 4:5, VERTICAL 9:16 and LANDSCAPE 1.91:1", + "enum": [ + "SQUARE", + "PORTRAIT", + "VERTICAL", + "LANDSCAPE" + ], + "type": "string" + }, + "fit": { + "description": "How an image of another shape reaches the ratio. CROP (the default) cuts it from the center; PAD keeps the whole image and fills the rest with a blurred copy of it", + "enum": [ + "CROP", + "PAD" + ], + "type": "string" + }, + "platform": { + "enum": [ + "INSTAGRAM", + "TIKTOK" + ], + "type": "string" + } + }, + "required": [ + "platform", + "aspectRatio" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / platformTexts / items / properties / text / descriptionAdded value: +"On LinkedIn, mention a company page with @[Page Name](urn:li:organization:<id>), using the page name exactly as LinkedIn shows it" - added
Input schema / properties / platformThumbnailsAdded value: +{ + "description": "A different thumbnail for one platform of a VIDEO post, one entry per platform. A platform without an entry uses the post-level thumbnailUrl and thumbnailTimestampMs. YOUTUBE, FACEBOOK and LINKEDIN take an image (thumbnailUrl); INSTAGRAM and PINTEREST take an image or a frame (thumbnailTimestampMs), the image winning when both are sent; TIKTOK takes only a frame. Posts that are not videos, Facebook and Instagram stories, a second entry for one platform and an entry the platform cannot use are refused with 400. On an update, sending the array replaces every override and omitting it keeps the stored ones", + "items": { + "additionalProperties": false, + "properties": { + "platform": { + "enum": [ + "YOUTUBE", + "FACEBOOK", + "LINKEDIN", + "INSTAGRAM", + "PINTEREST", + "TIKTOK" + ], + "type": "string" + }, + "thumbnailTimestampMs": { + "description": "The video frame (ms from the start) to use as this platform's thumbnail", + "minimum": 0, + "type": "integer" + }, + "thumbnailUrl": { + "description": "The image to use as this platform's thumbnail, an https URL or an image data URI", + "type": "string" + } + }, + "required": [ + "platform" + ], + "type": "object" + }, + "type": "array" +} - changed
Input schema / properties / platforms / descriptionPrevious value: -"Target platforms (e.g. [\"LINKEDIN\", \"TWITTER\"]). Each one needs its matching connection-id array (pageIds for FACEBOOK) filled with ids from list_accounts"New value: +"Target platforms (e.g. [\"LINKEDIN\", \"TWITTER\"]). Each one needs its matching connection-id array (pageIds for FACEBOOK, googleBusinessConnectionIds for GOOGLE_BUSINESS) filled with ids from list_accounts" - changed
Input schema / properties / platforms / items / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS" +] - changed
Input schema / properties / recurrence / properties / frequency / descriptionPrevious value: -"How often the post repeats: DAILY, WEEKLY, or MONTHLY"New value: +"How often the post repeats: DAILY, WEEKLY, MONTHLY or YEARLY. YEARLY repeats on the same date; a series started on February 29 posts on February 28 in other years" - changed
Input schema / properties / recurrence / properties / frequency / enumPrevious value: -[ - "DAILY", - "WEEKLY", - "MONTHLY" -]New value: +[ + "DAILY", + "WEEKLY", + "MONTHLY", + "YEARLY" +] - changed
Input schema / properties / recurrence / properties / interval / descriptionPrevious value: -"Repeat every N days, weeks or months, 1 to 30 (default 1)"New value: +"Repeat every N days, weeks, months or years, 1 to 30 (default 1)" - changed
Input schema / properties / text / descriptionPrevious value: -"Default post text shared across platforms"New value: +"Default post text shared across platforms. On LinkedIn, mention a company page with @[Page Name](urn:li:organization:<id>), using the page name exactly as LinkedIn shows it" - changed
Input schema / properties / thumbnailTimestampMs / descriptionPrevious value: -"Generate thumbnail from video at this timestamp (milliseconds)"New value: +"Video frame timestamp (ms) to use as the thumbnail, used by INSTAGRAM, PINTEREST and TIKTOK unless platformThumbnails overrides it" - changed
Input schema / properties / thumbnailUrl / descriptionPrevious value: -"Custom thumbnail image URL for video posts"New value: +"Video thumbnail as an https URL or an image data URI, used on every platform that takes one unless platformThumbnails overrides it" - added
Input schema / properties / twitterKeepLinksAdded value: +{ + "description": "Keep links in the X text clickable. X charges over 10 times more for a post with a link, so by default every link in X text is broken (example.com becomes example. com). Only AppSumo lifetime deals can turn this on, and a kept link costs 20 credits instead of 2. true on any other plan is refused with 400; it is ignored when the X text has no link", + "type": "boolean" +}
- Changed
generate_caption1 field changed- changed
Input schema / properties / platform / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS" +]
- Changed
get_analytics_overview2 fields changed- changed
Input schema / properties / platforms / descriptionPrevious value: -"Restrict to these platforms; omit for every platform with analytics. X (TWITTER) and MASTODON have no analytics and are ignored; LinkedIn analytics are pending platform approval and return no data yet"New value: +"Restrict to these platforms; omit for every platform with analytics. MASTODON and TELEGRAM have no analytics and are ignored. GOOGLE_BUSINESS reports location impressions only, with no per-post numbers" - changed
Input schema / properties / platforms / items / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS", + "TELEGRAM" +]
- Changed
get_analytics_timeseries2 fields changed- changed
Input schema / properties / platforms / descriptionPrevious value: -"Restrict to these platforms; omit for every platform with analytics. X (TWITTER) and MASTODON have no analytics and are ignored; LinkedIn analytics are pending platform approval and return no data yet"New value: +"Restrict to these platforms; omit for every platform with analytics. MASTODON and TELEGRAM have no analytics and are ignored. GOOGLE_BUSINESS reports location impressions only, with no per-post numbers" - changed
Input schema / properties / platforms / items / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS", + "TELEGRAM" +]
- Changed
get_post1 field changed- changed
Output schema / properties / result / descriptionPrevious value: -"The full post record: id, status, contentType, text, scheduledAt, timezone, mediaUrls, createdAt, updatedAt, recurringPostId and occurrenceAt (set when the post is an occurrence of a recurring post; occurrenceAt is its slot in the series and stays the same when the post is rescheduled), and platforms (one entry per target with id, platform, connectionId or pageId, status, errorMessage, platformPostId, postUrl once published, mediaUrls, previewUrls). previewUrls holds one permanent preview image per media item, a still frame for videos; after publishing, mediaUrls may become platform CDN links that expire within days, so show previewUrls instead."New value: +"The full post record: id, status, contentType, text, scheduledAt, timezone, mediaUrls, createdAt, updatedAt, recurringPostId and occurrenceAt (set when the post is an occurrence of a recurring post; occurrenceAt is its slot in the series and stays the same when the post is rescheduled), and platforms (one entry per target with id, platform, connectionId or pageId, status, errorMessage, platformPostId, postUrl once published, mediaUrls, previewUrls, and the per-platform settings: firstComment with firstCommentStatus PENDING, PUBLISHED or FAILED, firstCommentError and firstCommentPublishedAt; thumbnailUrl and thumbnailTimestampMs overrides; mediaAspectRatio and mediaAspectRatioFit; instagramCollaborators, instagramUsername and instagramAudioId, instagramAudioTitle, instagramAudioArtist, instagramAudioVolume, instagramVideoVolume; facebookTextFormatPresetId; twitterKeepLinks; googleBusinessTopicType, googleBusinessCallToActionType, googleBusinessCallToActionUrl, googleBusinessEventTitle, googleBusinessEventStart, googleBusinessEventEnd and googleBusinessOffer fields). postUrl links to the published post on every platform; Instagram and Facebook stories expire after 24 hours, so for them it links to the profile or page. A shareToStory story is its own entry with postType STORY. Posts created in the AdaptlyPost app can also target TELEGRAM, which this server cannot post to. previewUrls holds one permanent preview image per media item, a still frame for videos; after publishing, mediaUrls may become platform CDN links that expire within days, so show previewUrls instead."
- Changed
list_accounts1 field changed- changed
Output schema / properties / result / descriptionPrevious value: -"An object with accounts: one { id, platform, displayName, username, avatarUrl, status } per connected account, plus unauthorizedReason when status is unauthorized and pageId for Facebook pages. Use id as the connection id (or in pageIds for Facebook)."New value: +"An object with accounts: one { id, platform, displayName, username, avatarUrl, status } per connected account, plus unauthorizedReason when status is unauthorized, pageId for Facebook pages and supportsInstagramAudio for Instagram. Use id as the connection id (or in pageIds for Facebook)."
- Changed
list_post_analytics2 fields changed- changed
Input schema / properties / platforms / descriptionPrevious value: -"Restrict to these platforms; omit for every platform with analytics. X (TWITTER) and MASTODON have no analytics and are ignored; LinkedIn analytics are pending platform approval and return no data yet"New value: +"Restrict to these platforms; omit for every platform with analytics. MASTODON and TELEGRAM have no analytics and are ignored. GOOGLE_BUSINESS reports location impressions only, with no per-post numbers" - changed
Input schema / properties / platforms / items / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS", + "TELEGRAM" +]
- Changed
list_posts2 fields changed- changed
Input schema / properties / platforms / descriptionPrevious value: -"Filter to posts targeting any of these platforms"New value: +"Filter to posts targeting any of these platforms. TELEGRAM matches posts created in the AdaptlyPost app" - changed
Input schema / properties / platforms / items / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS", + "TELEGRAM" +]
- Changed
refine_caption1 field changed- changed
Input schema / properties / platform / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS" +]
- Added
search_instagram_audio - Changed
update_post22 fields changed- changed
Input schema / properties / contentType / descriptionPrevious value: -"New content type; must match the media on the post. DOCUMENT publishes one PDF, PPT, PPTX, DOC or DOCX file (max 100 MB, 300 pages) as a LinkedIn document post and is LinkedIn only: put exactly that one file in mediaUrls, target only LINKEDIN, and set the title with linkedinConfigs"New value: +"New content type; must match the media on the post. CAROUSEL takes 2 or more items in mediaUrls, up to 4 on TWITTER, BLUESKY and MASTODON, 5 on PINTEREST, 10 on INSTAGRAM, FACEBOOK and THREADS, 20 on LINKEDIN and 35 on TIKTOK (JPEG or WebP photos only). INSTAGRAM and THREADS accept images and videos in the same carousel; every other platform takes images only, and YOUTUBE has no carousel. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters. DOCUMENT publishes one PDF, PPT, PPTX, DOC or DOCX file (max 100 MB, 300 pages) as a LinkedIn document post and is LinkedIn only: put exactly that one file in mediaUrls, target only LINKEDIN, and set the title with linkedinConfigs" - changed
Input schema / properties / facebookConfigs / descriptionPrevious value: -"Facebook per-page config with post type and video title. pageId must match an entry in pageIds"New value: +"Facebook per-page config: post type, shareToStory, video title and text background. pageId must match an entry in pageIds" - changed
Input schema / properties / facebookConfigs / items / properties / postType / descriptionPrevious value: -"Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE or VIDEO. Any other combination is refused with 400"New value: +"Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE, VIDEO or CAROUSEL (a CAROUSEL story publishes each media item as its own story, in order). Any other combination is refused with 400" - added
Input schema / properties / facebookConfigs / items / properties / shareToStoryAdded value: +{ + "description": "Also publish the same media as a story on this page, next to the FEED or REEL post. The story shows as its own entry in platforms with postType STORY, so it succeeds, fails and retries on its own. It skips the caption, video title and text background, needs IMAGE, VIDEO or CAROUSEL, and a video must fit the story length limit (60 seconds). Ignored when postType is STORY", + "type": "boolean" +} - added
Input schema / properties / facebookConfigs / items / properties / textFormatPresetIdAdded value: +{ + "description": "Facebook's id for a colored text background (for example 106018623298955 is solid purple, 249307305544279 is a red to blue gradient). Only for contentType TEXT posts with no media and text up to 130 characters; anything else is refused with 400. Links in the text show without a preview. If Facebook refuses the background, the post goes out as plain text", + "pattern": "^\\d{1,20}$", + "type": "string" +} - added
Input schema / properties / firstCommentsAdded value: +{ + "description": "A comment posted from the same account right after the post goes out on a platform, one entry per platform. Available on LINKEDIN (1250 characters), TWITTER (280, as a reply), THREADS (500, as a reply), BLUESKY (300, as a reply), MASTODON (500, as a reply) and YOUTUBE (10000). A platform the post does not go to, an empty or too long comment, a second entry for one platform, a private or made for kids YouTube video and Facebook or Instagram stories are refused with 400. The comment is posted about 10 seconds after the platform publishes (60 on YouTube) and retried up to 3 times; on X it is not retried, and a lifetime-deal account pays for it like any X post. A comment that fails never fails the post: read firstCommentStatus and firstCommentError on the platform in get_post. On an update, sending the array replaces every first comment and omitting it keeps the stored ones", + "items": { + "additionalProperties": false, + "properties": { + "platform": { + "enum": [ + "LINKEDIN", + "TWITTER", + "THREADS", + "BLUESKY", + "MASTODON", + "YOUTUBE" + ], + "type": "string" + }, + "text": { + "description": "The comment's text, trimmed. The limit depends on the platform, see firstComments", + "maxLength": 10000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "platform", + "text" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / googleBusinessConfigsAdded value: +{ + "description": "Google Business Profile per-location config: update, event or offer, plus a button. connectionId must match an entry in googleBusinessConnectionIds. GOOGLE_BUSINESS takes TEXT or IMAGE with one JPEG or PNG image up to 5 MB, and text up to 1500 characters", + "items": { + "additionalProperties": false, + "properties": { + "callToActionType": { + "description": "Button shown on the post. Every type except CALL needs callToActionUrl; CALL dials the phone number on the Business Profile", + "enum": [ + "BOOK", + "ORDER", + "SHOP", + "LEARN_MORE", + "SIGN_UP", + "CALL" + ], + "type": "string" + }, + "callToActionUrl": { + "description": "Ignored when callToActionType is CALL", + "format": "uri", + "type": "string" + }, + "connectionId": { + "description": "Google Business Profile account id from list_accounts", + "type": "string" + }, + "eventEnd": { + "$ref": "#/properties/googleBusinessConfigs/items/properties/eventStart", + "description": "YYYY-MM-DD or YYYY-MM-DDTHH:mm in the business's local time, with no offset (e.g. \"2026-10-01T21:00\")" + }, + "eventStart": { + "description": "YYYY-MM-DD or YYYY-MM-DDTHH:mm in the business's local time, with no offset (e.g. \"2026-10-01T18:00\"). Google reads event times in the location's time zone", + "pattern": "^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2})?$", + "type": "string" + }, + "eventTitle": { + "description": "Title of the event or offer", + "type": "string" + }, + "offerCouponCode": { + "description": "OFFER only: coupon code", + "type": "string" + }, + "offerRedeemUrl": { + "description": "OFFER only: where the offer is redeemed", + "format": "uri", + "type": "string" + }, + "offerTerms": { + "description": "OFFER only: terms and conditions", + "type": "string" + }, + "topicType": { + "description": "STANDARD is an update. EVENT and OFFER need eventTitle, eventStart and eventEnd", + "enum": [ + "STANDARD", + "EVENT", + "OFFER" + ], + "type": "string" + } + }, + "required": [ + "connectionId", + "topicType" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / googleBusinessConnectionIdsAdded value: +{ + "description": "Google Business Profile locations to post to, by the account id from list_accounts. A location without an entry in googleBusinessConfigs gets a STANDARD update", + "items": { + "type": "string" + }, + "type": "array" +} - changed
Input schema / properties / instagramConfigs / descriptionPrevious value: -"Instagram per-connection config to set post type (FEED, REEL, STORY) and publish a reel as a trial reel"New value: +"Instagram per-connection config: post type (FEED, REEL, STORY), shareToStory, collaborators, Reel audio, and trial reels" - added
Input schema / properties / instagramConfigs / items / properties / audioAdded value: +{ + "additionalProperties": false, + "description": "Music or an original sound from Instagram's audio library, added to the Reel when it is published. Needs contentType VIDEO and a postType other than STORY, and only works for accounts with supportsInstagramAudio: true in list_accounts (connected through Facebook). Find ids with search_instagram_audio", + "properties": { + "artist": { + "description": "Artist or creator, stored for display only", + "maxLength": 255, + "type": "string" + }, + "audioId": { + "description": "audioId from search_instagram_audio", + "maxLength": 64, + "minLength": 1, + "type": "string" + }, + "audioVolume": { + "description": "Volume of the added audio, 1 to 100. Defaults to 100", + "maximum": 100, + "minimum": 1, + "type": "integer" + }, + "title": { + "description": "Track title, stored for display only", + "maxLength": 255, + "type": "string" + }, + "videoVolume": { + "description": "Volume of the video's own sound, 1 to 100. Defaults to 100", + "maximum": 100, + "minimum": 1, + "type": "integer" + } + }, + "required": [ + "audioId" + ], + "type": "object" +} - added
Input schema / properties / instagramConfigs / items / properties / collaboratorsAdded value: +{ + "description": "Instagram usernames invited as collaborators (Instagram Collab), up to 3. A leading @ is stripped and duplicates are dropped. Works on feed images, carousels and reels; a story or a trial reel with collaborators is refused with 400. Each collaborator gets an invite in Instagram and must accept it before the post shows on their profile", + "items": { + "pattern": "^@?[A-Za-z0-9._]{1,30}$", + "type": "string" + }, + "maxItems": 3, + "type": "array" +} - changed
Input schema / properties / instagramConfigs / items / properties / postType / descriptionPrevious value: -"Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE or VIDEO. Any other combination is refused with 400"New value: +"Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE, VIDEO or CAROUSEL (a CAROUSEL story publishes each media item as its own story, in order). Any other combination is refused with 400" - added
Input schema / properties / instagramConfigs / items / properties / shareToStoryAdded value: +{ + "description": "Also publish the same media as a story on this account, next to the FEED or REEL post. The story shows as its own entry in platforms with postType STORY, so it succeeds, fails and retries on its own. It skips the caption, first comment, cover, collaborators, trial and audio, needs IMAGE, VIDEO or CAROUSEL, and a video must fit the story length limit (60 seconds). Ignored when postType is STORY", + "type": "boolean" +} - changed
Input schema / properties / mediaAltTexts / descriptionPrevious value: -"Alt text per image, in the same order as mediaUrls (max 1000 characters each; use \"\" to skip an image). Sent to X, Bluesky, Mastodon, LinkedIn, Facebook, Instagram and Threads; Pinterest uses the first one (cut to 500). TikTok, YouTube and videos ignore it. Applied only when platforms is also sent"New value: +"Alt text per image, in the same order as mediaUrls (max 1000 characters each; use \"\" to skip an image). Sent to X, Bluesky, Mastodon, LinkedIn, Facebook, Instagram and Threads; Pinterest uses the first one (cut to 500). TikTok, YouTube, Google Business Profile and videos ignore it. Applied only when platforms is also sent" - added
Input schema / properties / platformAspectRatiosAdded value: +{ + "description": "Reframe every image of an IMAGE or CAROUSEL post to one shape on a platform, one entry per platform. INSTAGRAM takes SQUARE, PORTRAIT or LANDSCAPE (Instagram refuses 9:16 feed and carousel images); TIKTOK takes all four. Video posts, Instagram stories and a second entry for the same platform are refused with 400. Omit a platform to keep its images as uploaded. On an update it applies to the mediaUrls sent in the same request", + "items": { + "additionalProperties": false, + "properties": { + "aspectRatio": { + "description": "SQUARE is 1:1, PORTRAIT 4:5, VERTICAL 9:16 and LANDSCAPE 1.91:1", + "enum": [ + "SQUARE", + "PORTRAIT", + "VERTICAL", + "LANDSCAPE" + ], + "type": "string" + }, + "fit": { + "description": "How an image of another shape reaches the ratio. CROP (the default) cuts it from the center; PAD keeps the whole image and fills the rest with a blurred copy of it", + "enum": [ + "CROP", + "PAD" + ], + "type": "string" + }, + "platform": { + "enum": [ + "INSTAGRAM", + "TIKTOK" + ], + "type": "string" + } + }, + "required": [ + "platform", + "aspectRatio" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / platformTexts / items / properties / text / descriptionAdded value: +"On LinkedIn, mention a company page with @[Page Name](urn:li:organization:<id>), using the page name exactly as LinkedIn shows it" - added
Input schema / properties / platformThumbnailsAdded value: +{ + "description": "A different thumbnail for one platform of a VIDEO post, one entry per platform. A platform without an entry uses the post-level thumbnailUrl and thumbnailTimestampMs. YOUTUBE, FACEBOOK and LINKEDIN take an image (thumbnailUrl); INSTAGRAM and PINTEREST take an image or a frame (thumbnailTimestampMs), the image winning when both are sent; TIKTOK takes only a frame. Posts that are not videos, Facebook and Instagram stories, a second entry for one platform and an entry the platform cannot use are refused with 400. On an update, sending the array replaces every override and omitting it keeps the stored ones", + "items": { + "additionalProperties": false, + "properties": { + "platform": { + "enum": [ + "YOUTUBE", + "FACEBOOK", + "LINKEDIN", + "INSTAGRAM", + "PINTEREST", + "TIKTOK" + ], + "type": "string" + }, + "thumbnailTimestampMs": { + "description": "The video frame (ms from the start) to use as this platform's thumbnail", + "minimum": 0, + "type": "integer" + }, + "thumbnailUrl": { + "description": "The image to use as this platform's thumbnail, an https URL or an image data URI", + "type": "string" + } + }, + "required": [ + "platform" + ], + "type": "object" + }, + "type": "array" +} - changed
Input schema / properties / platforms / items / enumPrevious value: -[ - "LINKEDIN", - "YOUTUBE", - "INSTAGRAM", - "FACEBOOK", - "TIKTOK", - "PINTEREST", - "THREADS", - "BLUESKY", - "TWITTER", - "MASTODON" -]New value: +[ + "LINKEDIN", + "YOUTUBE", + "INSTAGRAM", + "FACEBOOK", + "TIKTOK", + "PINTEREST", + "THREADS", + "BLUESKY", + "TWITTER", + "MASTODON", + "GOOGLE_BUSINESS" +] - changed
Input schema / properties / text / descriptionPrevious value: -"Updated text; omit to keep the current text"New value: +"Updated text; omit to keep the current text. On LinkedIn, mention a company page with @[Page Name](urn:li:organization:<id>), using the page name exactly as LinkedIn shows it" - changed
Input schema / properties / thumbnailTimestampMs / descriptionPrevious value: -"Generate thumbnail from video at this timestamp (milliseconds)"New value: +"Video frame timestamp (ms) to use as the thumbnail, used by INSTAGRAM, PINTEREST and TIKTOK unless platformThumbnails overrides it" - changed
Input schema / properties / thumbnailUrl / descriptionPrevious value: -"Custom thumbnail image URL for video posts"New value: +"Video thumbnail as an https URL or an image data URI, used on every platform that takes one unless platformThumbnails overrides it" - added
Input schema / properties / twitterKeepLinksAdded value: +{ + "description": "Keep links in the X text clickable. X charges over 10 times more for a post with a link, so by default every link in X text is broken (example.com becomes example. com). Only AppSumo lifetime deals can turn this on, and a kept link costs 20 credits instead of 2. true on any other plan is refused with 400; it is ignored when the X text has no link", + "type": "boolean" +}
2 tool updates
- Added
get_upload_ticket - Added
open_upload_widget
2 tool updates
- Changed
generate_caption1 field changed- changed
Input schema / properties / platform / descriptionPrevious value: -"Platform the caption is for; the caption is kept within that platform's character limit. Omit for a general caption"New value: +"Platform the caption is for; generation targets that platform's character limit; check the returned text before posting. Omit for a general caption"
- Changed
refine_caption1 field changed- changed
Input schema / properties / platform / descriptionPrevious value: -"Platform the caption is for; the result is kept within that platform's character limit"New value: +"Platform the caption is for; generation targets that platform's character limit; check the returned text before posting"
29 tool updates
- Changed
bulk_schedule_posts2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
create_post2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
delete_post2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
delete_recurring_post2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
generate_caption2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
generate_image2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
get_analytics_overview2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
get_analytics_sync_status2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
get_analytics_timeseries2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
get_image_job2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
get_platform_breakdown2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
get_post2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
get_recurring_post2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
get_upload_urls2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
list_accounts2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
list_post_analytics2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
list_post_results2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
list_posts2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
list_recurring_posts2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
list_workspaces2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
pause_recurring_post2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
publish_draft2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
refine_caption2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
resume_recurring_post2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
retry_failed_platforms2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
trigger_analytics_sync2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
unschedule_post2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
update_post2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
upload_media2 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
29 tool updates
- Changed
bulk_schedule_posts33 fields changed- added
Input schema / properties / facebookConfigs / items / $refAdded value: +"#/properties/posts/items/properties/facebookConfigs/items" - removed
Input schema / properties / facebookConfigs / items / additionalPropertiesRemoved value: -false - removed
Input schema / properties / facebookConfigs / items / propertiesRemoved value: -{ - "pageId": { - "description": "Facebook page ID from list_accounts", - "type": "string" - }, - "postType": { - "description": "Facebook post type — FEED, REEL, or STORY", - "enum": [ - "FEED", - "REEL", - "STORY" - ], - "type": "string" - }, - "videoTitle": { - "description": "Video title for Facebook (max 255 chars)", - "maxLength": 255, - "type": "string" - } -} - removed
Input schema / properties / facebookConfigs / items / requiredRemoved value: -[ - "pageId" -] - removed
Input schema / properties / facebookConfigs / items / typeRemoved value: -"object" - added
Input schema / properties / instagramConfigs / items / $refAdded value: +"#/properties/posts/items/properties/instagramConfigs/items" - removed
Input schema / properties / instagramConfigs / items / additionalPropertiesRemoved value: -false - removed
Input schema / properties / instagramConfigs / items / propertiesRemoved value: -{ - "connectionId": { - "description": "Instagram connection ID from list_accounts", - "type": "string" - }, - "postType": { - "description": "Instagram post type — FEED, REEL, or STORY", - "enum": [ - "FEED", - "REEL", - "STORY" - ], - "type": "string" - }, - "trialGraduation": { - "description": "Publish a video reel as a trial reel: Instagram shows it to non-followers first and keeps it off followers' feeds and the profile grid until it is shared. MANUAL means the account owner shares it from the Instagram app; SS_PERFORMANCE means Instagram shares it if it performs well. Only for a single video posted as a reel or feed video, never a story, image or carousel (400 otherwise). Needs a professional account Instagram has enabled for trial reels; otherwise that platform fails with a message saying so", - "enum": [ - "MANUAL", - "SS_PERFORMANCE" - ], - "type": "string" - } -} - removed
Input schema / properties / instagramConfigs / items / requiredRemoved value: -[ - "connectionId" -] - removed
Input schema / properties / instagramConfigs / items / typeRemoved value: -"object" - added
Input schema / properties / pinterestConfigs / items / $refAdded value: +"#/properties/posts/items/properties/pinterestConfigs/items" - removed
Input schema / properties / pinterestConfigs / items / additionalPropertiesRemoved value: -false - removed
Input schema / properties / pinterestConfigs / items / propertiesRemoved value: -{ - "boardId": { - "description": "Pinterest board ID to pin to (required)", - "type": "string" - }, - "connectionId": { - "description": "Pinterest connection ID from list_accounts", - "type": "string" - }, - "link": { - "description": "Destination URL for the pin", - "type": "string" - }, - "title": { - "description": "Pin title (max 100 chars)", - "maxLength": 100, - "type": "string" - } -} - removed
Input schema / properties / pinterestConfigs / items / requiredRemoved value: -[ - "connectionId", - "boardId" -] - removed
Input schema / properties / pinterestConfigs / items / typeRemoved value: -"object" - added
Input schema / properties / posts / items / properties / facebookConfigsAdded value: +{ + "description": "Facebook config for this item only; replaces the batch-level facebookConfigs", + "items": { + "additionalProperties": false, + "properties": { + "pageId": { + "description": "Facebook page ID from list_accounts", + "type": "string" + }, + "postType": { + "description": "Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE or VIDEO. Any other combination is refused with 400", + "enum": [ + "FEED", + "REEL", + "STORY" + ], + "type": "string" + }, + "videoTitle": { + "description": "Video title for Facebook (max 255 chars)", + "maxLength": 255, + "type": "string" + } + }, + "required": [ + "pageId" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / posts / items / properties / instagramConfigsAdded value: +{ + "description": "Instagram config for this item only; replaces the batch-level instagramConfigs", + "items": { + "additionalProperties": false, + "properties": { + "connectionId": { + "description": "Instagram connection ID from list_accounts", + "type": "string" + }, + "postType": { + "description": "Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE or VIDEO. Any other combination is refused with 400", + "enum": [ + "FEED", + "REEL", + "STORY" + ], + "type": "string" + }, + "trialGraduation": { + "description": "Publish a video reel as a trial reel: Instagram shows it to non-followers first and keeps it off followers' feeds and the profile grid until it is shared. MANUAL means the account owner shares it from the Instagram app; SS_PERFORMANCE means Instagram shares it if it performs well. Only for a single video posted as a reel or feed video, never a story, image or carousel (400 otherwise). Needs a professional account Instagram has enabled for trial reels; otherwise that platform fails with a message saying so", + "enum": [ + "MANUAL", + "SS_PERFORMANCE" + ], + "type": "string" + } + }, + "required": [ + "connectionId" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / posts / items / properties / pinterestConfigsAdded value: +{ + "description": "Pinterest config for this item only, such as its own title or link; replaces the batch-level pinterestConfigs", + "items": { + "additionalProperties": false, + "properties": { + "boardId": { + "description": "Pinterest board ID to pin to (required)", + "type": "string" + }, + "connectionId": { + "description": "Pinterest connection ID from list_accounts", + "type": "string" + }, + "link": { + "description": "Destination URL for the pin", + "type": "string" + }, + "title": { + "description": "Pin title (max 100 chars)", + "maxLength": 100, + "type": "string" + } + }, + "required": [ + "connectionId", + "boardId" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / posts / items / properties / tiktokConfigsAdded value: +{ + "description": "TikTok config for this item only; replaces the batch-level tiktokConfigs", + "items": { + "additionalProperties": false, + "properties": { + "aiGenerated": { + "description": "Label content as AI-generated", + "type": "boolean" + }, + "allowComments": { + "description": "Allow comments on the TikTok post", + "type": "boolean" + }, + "allowDuet": { + "description": "Allow other users to Duet this video", + "type": "boolean" + }, + "allowStitch": { + "description": "Allow other users to Stitch this video", + "type": "boolean" + }, + "autoAddMusic": { + "description": "Let TikTok auto-add music to the video", + "type": "boolean" + }, + "brandedContent": { + "description": "Disclose as branded content (paid partnership)", + "type": "boolean" + }, + "brandedContentOwnBrand": { + "description": "Disclose as promoting your own brand", + "type": "boolean" + }, + "caption": { + "description": "TikTok-specific caption (max 2200 chars)", + "maxLength": 2200, + "type": "string" + }, + "connectionId": { + "description": "TikTok connection ID from list_accounts", + "type": "string" + }, + "privacyLevel": { + "description": "TikTok privacy level", + "enum": [ + "PUBLIC_TO_EVERYONE", + "MUTUAL_FOLLOW_FRIENDS", + "FOLLOWER_OF_CREATOR", + "SELF_ONLY" + ], + "type": "string" + }, + "sendAsDraft": { + "description": "Save as TikTok draft so the user can add trending sounds before publishing", + "type": "boolean" + }, + "title": { + "description": "Video title (max 90 chars)", + "maxLength": 90, + "type": "string" + } + }, + "required": [ + "connectionId", + "privacyLevel" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / posts / items / properties / youtubeConfigsAdded value: +{ + "description": "YouTube config for this item only, such as its own videoTitle; replaces the batch-level youtubeConfigs", + "items": { + "additionalProperties": false, + "properties": { + "allowEmbedding": { + "description": "Allow embedding the video on other sites", + "type": "boolean" + }, + "categoryId": { + "description": "YouTube category ID", + "type": "string" + }, + "connectionId": { + "description": "YouTube connection ID from list_accounts", + "type": "string" + }, + "license": { + "description": "Video license type", + "enum": [ + "youtube", + "creativeCommon" + ], + "type": "string" + }, + "madeForKids": { + "description": "Mark the video as made for kids (COPPA)", + "type": "boolean" + }, + "notifySubscribers": { + "description": "Notify channel subscribers about the upload", + "type": "boolean" + }, + "playlistId": { + "description": "Add video to this playlist", + "type": "string" + }, + "postType": { + "description": "VIDEO for long-form, SHORTS for YouTube Shorts", + "enum": [ + "VIDEO", + "SHORTS" + ], + "type": "string" + }, + "privacyStatus": { + "description": "Video privacy status", + "enum": [ + "public", + "private", + "unlisted" + ], + "type": "string" + }, + "tags": { + "description": "Video tags (max 20)", + "items": { + "type": "string" + }, + "maxItems": 20, + "type": "array" + }, + "videoTitle": { + "description": "YouTube video title (max 100 chars)", + "maxLength": 100, + "type": "string" + } + }, + "required": [ + "connectionId" + ], + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / posts / maxItemsAdded value: +100 - added
Input schema / properties / posts / minItemsAdded value: +1 - added
Input schema / properties / tiktokConfigs / items / $refAdded value: +"#/properties/posts/items/properties/tiktokConfigs/items" - removed
Input schema / properties / tiktokConfigs / items / additionalPropertiesRemoved value: -false - removed
Input schema / properties / tiktokConfigs / items / propertiesRemoved value: -{ - "aiGenerated": { - "description": "Label content as AI-generated", - "type": "boolean" - }, - "allowComments": { - "description": "Allow comments on the TikTok post", - "type": "boolean" - }, - "allowDuet": { - "description": "Allow other users to Duet this video", - "type": "boolean" - }, - "allowStitch": { - "description": "Allow other users to Stitch this video", - "type": "boolean" - }, - "autoAddMusic": { - "description": "Let TikTok auto-add music to the video", - "type": "boolean" - }, - "brandedContent": { - "description": "Disclose as branded content (paid partnership)", - "type": "boolean" - }, - "brandedContentOwnBrand": { - "description": "Disclose as promoting your own brand", - "type": "boolean" - }, - "caption": { - "description": "TikTok-specific caption (max 2200 chars)", - "maxLength": 2200, - "type": "string" - }, - "connectionId": { - "description": "TikTok connection ID from list_accounts", - "type": "string" - }, - "privacyLevel": { - "description": "TikTok privacy level", - "enum": [ - "PUBLIC_TO_EVERYONE", - "MUTUAL_FOLLOW_FRIENDS", - "FOLLOWER_OF_CREATOR", - "SELF_ONLY" - ], - "type": "string" - }, - "sendAsDraft": { - "description": "Save as TikTok draft so the user can add trending sounds before publishing", - "type": "boolean" - }, - "title": { - "description": "Video title (max 90 chars)", - "maxLength": 90, - "type": "string" - } -} - removed
Input schema / properties / tiktokConfigs / items / requiredRemoved value: -[ - "connectionId", - "privacyLevel" -] - removed
Input schema / properties / tiktokConfigs / items / typeRemoved value: -"object" - changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another" - added
Input schema / properties / youtubeConfigs / items / $refAdded value: +"#/properties/posts/items/properties/youtubeConfigs/items" - removed
Input schema / properties / youtubeConfigs / items / additionalPropertiesRemoved value: -false - removed
Input schema / properties / youtubeConfigs / items / propertiesRemoved value: -{ - "allowEmbedding": { - "description": "Allow embedding the video on other sites", - "type": "boolean" - }, - "categoryId": { - "description": "YouTube category ID", - "type": "string" - }, - "connectionId": { - "description": "YouTube connection ID from list_accounts", - "type": "string" - }, - "license": { - "description": "Video license type", - "enum": [ - "youtube", - "creativeCommon" - ], - "type": "string" - }, - "madeForKids": { - "description": "Mark the video as made for kids (COPPA)", - "type": "boolean" - }, - "notifySubscribers": { - "description": "Notify channel subscribers about the upload", - "type": "boolean" - }, - "playlistId": { - "description": "Add video to this playlist", - "type": "string" - }, - "postType": { - "description": "VIDEO for long-form, SHORTS for YouTube Shorts", - "enum": [ - "VIDEO", - "SHORTS" - ], - "type": "string" - }, - "privacyStatus": { - "description": "Video privacy status", - "enum": [ - "public", - "private", - "unlisted" - ], - "type": "string" - }, - "tags": { - "description": "Video tags (max 20)", - "items": { - "type": "string" - }, - "maxItems": 20, - "type": "array" - }, - "videoTitle": { - "description": "YouTube video title (max 100 chars)", - "maxLength": 100, - "type": "string" - } -} - removed
Input schema / properties / youtubeConfigs / items / requiredRemoved value: -[ - "connectionId" -] - removed
Input schema / properties / youtubeConfigs / items / typeRemoved value: -"object"
- Changed
create_post4 fields changed- changed
Input schema / properties / facebookConfigs / items / properties / postType / descriptionPrevious value: -"Facebook post type — FEED, REEL, or STORY"New value: +"Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE or VIDEO. Any other combination is refused with 400" - changed
Input schema / properties / instagramConfigs / items / properties / postType / descriptionPrevious value: -"Instagram post type — FEED, REEL, or STORY"New value: +"Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE or VIDEO. Any other combination is refused with 400" - added
Input schema / properties / recurrence / properties / weekdays / maxItemsAdded value: +7 - changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Changed
delete_post1 field changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Changed
delete_recurring_post1 field changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Added
generate_caption - Added
generate_image - Changed
get_analytics_overview1 field changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Changed
get_analytics_sync_status1 field changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Changed
get_analytics_timeseries1 field changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Added
get_image_job - Changed
get_platform_breakdown1 field changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Changed
get_post1 field changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Changed
get_recurring_post1 field changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Changed
get_upload_urls1 field changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Changed
list_accounts2 fields changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another" - changed
Output schema / properties / result / descriptionPrevious value: -"An object with accounts: one { id, platform, displayName, username, avatarUrl } per connected account, plus pageId for Facebook pages. Use id as the connection id (or in pageIds for Facebook)."New value: +"An object with accounts: one { id, platform, displayName, username, avatarUrl, status } per connected account, plus unauthorizedReason when status is unauthorized and pageId for Facebook pages. Use id as the connection id (or in pageIds for Facebook)."
- Changed
list_post_analytics6 fields changed- added
Input schema / properties / limit / maximumAdded value: +100 - added
Input schema / properties / limit / minimumAdded value: +1 - changed
Input schema / properties / limit / typePrevious value: -"number"New value: +"integer" - added
Input schema / properties / page / minimumAdded value: +1 - changed
Input schema / properties / page / typePrevious value: -"number"New value: +"integer" - changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Changed
list_post_results2 fields changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another" - changed
Output schema / properties / result / descriptionPrevious value: -"An object with postId, the overall post status, and results: one { platformId, platform, accountName, status, platformPostId, errorMessage, publishedAt } per targeted platform."New value: +"An object with postId, the overall post status, and results: one { platformId, platform, accountName, status, platformPostId, errorMessage, tiktokDraftFallback, publishedAt } per targeted platform."
- Changed
list_posts6 fields changed- added
Input schema / properties / limit / maximumAdded value: +100 - added
Input schema / properties / limit / minimumAdded value: +1 - changed
Input schema / properties / limit / typePrevious value: -"number"New value: +"integer" - added
Input schema / properties / offset / minimumAdded value: +0 - changed
Input schema / properties / offset / typePrevious value: -"number"New value: +"integer" - changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Changed
list_recurring_posts6 fields changed- added
Input schema / properties / limit / maximumAdded value: +100 - added
Input schema / properties / limit / minimumAdded value: +1 - changed
Input schema / properties / limit / typePrevious value: -"number"New value: +"integer" - added
Input schema / properties / offset / minimumAdded value: +0 - changed
Input schema / properties / offset / typePrevious value: -"number"New value: +"integer" - changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Changed
list_workspaces1 field changed- changed
Output schema / properties / result / descriptionPrevious value: -"An object with workspaces: one { id, name, organization, role, isDefault, current, can } per workspace. Pass id as workspaceId to other tools."New value: +"An object with workspaces: one { id, name, organization, role, permissions, isDefault, current, can } per workspace. Pass id as workspaceId to other tools."
- Changed
pause_recurring_post1 field changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Changed
publish_draft1 field changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Added
refine_caption - Changed
resume_recurring_post1 field changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Changed
retry_failed_platforms1 field changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Changed
trigger_analytics_sync1 field changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Changed
unschedule_post1 field changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Changed
update_post4 fields changed- changed
Input schema / properties / facebookConfigs / items / properties / postType / descriptionPrevious value: -"Facebook post type — FEED, REEL, or STORY"New value: +"Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE or VIDEO. Any other combination is refused with 400" - changed
Input schema / properties / instagramConfigs / items / properties / postType / descriptionPrevious value: -"Instagram post type — FEED, REEL, or STORY"New value: +"Where the post goes: FEED works with every content type, REEL needs contentType VIDEO, STORY needs IMAGE or VIDEO. Any other combination is refused with 400" - changed
Input schema / properties / mediaAltTexts / descriptionPrevious value: -"Alt text per image, in the same order as mediaUrls (max 1000 characters each; use \"\" to skip an image). Sent to X, Bluesky, Mastodon, LinkedIn, Facebook, Instagram and Threads; Pinterest uses the first one (cut to 500). TikTok, YouTube and videos ignore it"New value: +"Alt text per image, in the same order as mediaUrls (max 1000 characters each; use \"\" to skip an image). Sent to X, Bluesky, Mastodon, LinkedIn, Facebook, Instagram and Threads; Pinterest uses the first one (cut to 500). TikTok, YouTube and videos ignore it. Applied only when platforms is also sent" - changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
- Changed
upload_media1 field changed- changed
Input schema / properties / workspaceId / descriptionPrevious value: -"Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"New value: +"Workspace to act in: an id from list_workspaces. Omit to act in the workspace list_workspaces marks current. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another"
25 tool updates
- Changed
bulk_schedule_posts1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
create_post1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
delete_post1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
delete_recurring_post1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
get_analytics_overview1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
get_analytics_sync_status2 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
get_analytics_timeseries1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
get_platform_breakdown1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
get_post1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
get_recurring_post1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
get_upload_urls1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
list_accounts2 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
list_post_analytics1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
list_post_results1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
list_posts1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
list_recurring_posts1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Added
list_workspaces - Changed
pause_recurring_post1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
publish_draft1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
resume_recurring_post1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
retry_failed_platforms1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
trigger_analytics_sync2 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
unschedule_post1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
update_post1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
- Changed
upload_media1 field changed- added
Input schema / properties / workspaceIdAdded value: +{ + "description": "Workspace to act in: an id from list_workspaces. Omit to use the default workspace. Use the same workspaceId for every call about the same workspace, since ids from one workspace (accounts, posts, uploads) do not exist in another", + "type": "string" +}
3 tool updates
- Changed
bulk_schedule_posts2 fields changed- changed
Input schema / properties / instagramConfigs / descriptionPrevious value: -"Instagram per-connection config to set post type (FEED, REEL, STORY)"New value: +"Instagram per-connection config to set post type (FEED, REEL, STORY) and publish a reel as a trial reel" - added
Input schema / properties / instagramConfigs / items / properties / trialGraduationAdded value: +{ + "description": "Publish a video reel as a trial reel: Instagram shows it to non-followers first and keeps it off followers' feeds and the profile grid until it is shared. MANUAL means the account owner shares it from the Instagram app; SS_PERFORMANCE means Instagram shares it if it performs well. Only for a single video posted as a reel or feed video, never a story, image or carousel (400 otherwise). Needs a professional account Instagram has enabled for trial reels; otherwise that platform fails with a message saying so", + "enum": [ + "MANUAL", + "SS_PERFORMANCE" + ], + "type": "string" +}
- Changed
create_post2 fields changed- changed
Input schema / properties / instagramConfigs / descriptionPrevious value: -"Instagram per-connection config to set post type (FEED, REEL, STORY)"New value: +"Instagram per-connection config to set post type (FEED, REEL, STORY) and publish a reel as a trial reel" - added
Input schema / properties / instagramConfigs / items / properties / trialGraduationAdded value: +{ + "description": "Publish a video reel as a trial reel: Instagram shows it to non-followers first and keeps it off followers' feeds and the profile grid until it is shared. MANUAL means the account owner shares it from the Instagram app; SS_PERFORMANCE means Instagram shares it if it performs well. Only for a single video posted as a reel or feed video, never a story, image or carousel (400 otherwise). Needs a professional account Instagram has enabled for trial reels; otherwise that platform fails with a message saying so", + "enum": [ + "MANUAL", + "SS_PERFORMANCE" + ], + "type": "string" +}
- Changed
update_post2 fields changed- changed
Input schema / properties / instagramConfigs / descriptionPrevious value: -"Instagram per-connection config to set post type (FEED, REEL, STORY)"New value: +"Instagram per-connection config to set post type (FEED, REEL, STORY) and publish a reel as a trial reel" - added
Input schema / properties / instagramConfigs / items / properties / trialGraduationAdded value: +{ + "description": "Publish a video reel as a trial reel: Instagram shows it to non-followers first and keeps it off followers' feeds and the profile grid until it is shared. MANUAL means the account owner shares it from the Instagram app; SS_PERFORMANCE means Instagram shares it if it performs well. Only for a single video posted as a reel or feed video, never a story, image or carousel (400 otherwise). Needs a professional account Instagram has enabled for trial reels; otherwise that platform fails with a message saying so", + "enum": [ + "MANUAL", + "SS_PERFORMANCE" + ], + "type": "string" +}
8 tool updates
- Changed
create_post2 fields changed- added
Input schema / properties / recurrenceAdded value: +{ + "additionalProperties": false, + "description": "Repeat the post on a schedule. Needs a future scheduledAt, which becomes the first post and sets the time of day in timezone. Cannot be combined with saveAsDraft or TIKTOK. Missed slots, for example while paused, are skipped and never published late. X and LinkedIn reject identical text, so use spintax such as {Hi|Hello} to vary each post. Manage the series with list_recurring_posts, pause_recurring_post, resume_recurring_post and delete_recurring_post", + "properties": { + "endsOn": { + "description": "Last day an occurrence may go out on, as YYYY-MM-DD (inclusive). Must be on or after the day of the first post. Cannot be combined with maxOccurrences", + "type": "string" + }, + "frequency": { + "description": "How often the post repeats: DAILY, WEEKLY, or MONTHLY", + "enum": [ + "DAILY", + "WEEKLY", + "MONTHLY" + ], + "type": "string" + }, + "interval": { + "description": "Repeat every N days, weeks or months, 1 to 30 (default 1)", + "maximum": 30, + "minimum": 1, + "type": "integer" + }, + "maxOccurrences": { + "description": "Total number of posts the series publishes, 2 to 365. Cannot be combined with endsOn; omit both to repeat until paused or deleted", + "maximum": 365, + "minimum": 2, + "type": "integer" + }, + "weekdays": { + "description": "WEEKLY only: the weekdays it goes out on (e.g. [\"MONDAY\", \"THURSDAY\"]). The weekday of scheduledAt is always included", + "items": { + "enum": [ + "MONDAY", + "TUESDAY", + "WEDNESDAY", + "THURSDAY", + "FRIDAY", + "SATURDAY", + "SUNDAY" + ], + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "frequency" + ], + "type": "object" +} - changed
Output schema / properties / result / descriptionPrevious value: -"An object with postId, queuedPlatforms (platforms whose publishing job was queued; empty for scheduled posts and drafts), skippedPlatforms, isScheduled, and scheduledAt. Publishing is asynchronous: check list_post_results for outcomes."New value: +"An object with postId, queuedPlatforms (platforms whose publishing job was queued; empty for scheduled posts and drafts), skippedPlatforms, isScheduled, and scheduledAt, plus recurringPostId when recurrence was sent. Publishing is asynchronous: check list_post_results for outcomes."
- Added
delete_recurring_post - Changed
get_post1 field changed- changed
Output schema / properties / result / descriptionPrevious value: -"The full post record: id, status, contentType, text, scheduledAt, timezone, mediaUrls, createdAt, updatedAt, and platforms (one entry per target with id, platform, connectionId or pageId, status, errorMessage, platformPostId, postUrl once published, mediaUrls, previewUrls). previewUrls holds one permanent preview image per media item, a still frame for videos; after publishing, mediaUrls may become platform CDN links that expire within days, so show previewUrls instead."New value: +"The full post record: id, status, contentType, text, scheduledAt, timezone, mediaUrls, createdAt, updatedAt, recurringPostId and occurrenceAt (set when the post is an occurrence of a recurring post; occurrenceAt is its slot in the series and stays the same when the post is rescheduled), and platforms (one entry per target with id, platform, connectionId or pageId, status, errorMessage, platformPostId, postUrl once published, mediaUrls, previewUrls). previewUrls holds one permanent preview image per media item, a still frame for videos; after publishing, mediaUrls may become platform CDN links that expire within days, so show previewUrls instead."
- Added
get_recurring_post - Changed
list_posts1 field changed- changed
Output schema / properties / result / descriptionPrevious value: -"An object with posts (each with id, status, contentType, text, scheduledAt, timezone, and platforms with per-platform status), total (count of all matches), and hasMore."New value: +"An object with posts (each with id, status, contentType, text, scheduledAt, timezone, recurringPostId and occurrenceAt for occurrences of a recurring post, and platforms with per-platform status), total (count of all matches), and hasMore."
- Added
list_recurring_posts - Added
pause_recurring_post - Added
resume_recurring_post
5 tool updates
- Changed
bulk_schedule_posts1 field changed- changed
Input schema / properties / posts / items / properties / contentType / descriptionPrevious value: -"TEXT, IMAGE, VIDEO, or CAROUSEL; must match mediaUrls"New value: +"TEXT, IMAGE, VIDEO, or CAROUSEL; must match mediaUrls. DOCUMENT posts cannot be bulk scheduled; use create_post"
- Changed
create_post3 fields changed- changed
Input schema / properties / contentType / descriptionPrevious value: -"Content type: TEXT, IMAGE, VIDEO, or CAROUSEL. Must match mediaUrls (CAROUSEL needs several)"New value: +"Content type: TEXT, IMAGE, VIDEO, CAROUSEL, or DOCUMENT. Must match mediaUrls (CAROUSEL needs several). DOCUMENT publishes one PDF, PPT, PPTX, DOC or DOCX file (max 100 MB, 300 pages) as a LinkedIn document post and is LinkedIn only: put exactly that one file in mediaUrls, target only LINKEDIN, and set the title with linkedinConfigs" - changed
Input schema / properties / contentType / enumPrevious value: -[ - "TEXT", - "IMAGE", - "VIDEO", - "CAROUSEL" -]New value: +[ + "TEXT", + "IMAGE", + "VIDEO", + "CAROUSEL", + "DOCUMENT" +] - added
Input schema / properties / linkedinConfigsAdded value: +{ + "description": "LinkedIn per-connection config: documentTitle names a DOCUMENT post. connectionId must match an entry in linkedinConnectionIds", + "items": { + "additionalProperties": false, + "properties": { + "connectionId": { + "description": "LinkedIn connection ID from list_accounts", + "type": "string" + }, + "documentTitle": { + "description": "Title LinkedIn shows on a DOCUMENT post (max 100 chars). Defaults to the file name; ignored for other content types", + "maxLength": 100, + "type": "string" + } + }, + "required": [ + "connectionId" + ], + "type": "object" + }, + "type": "array" +}
- Changed
get_upload_urls1 field changed- changed
Input schema / properties / files / items / properties / mimeType / enumPrevious value: -[ - "image/jpeg", - "image/png", - "image/webp", - "video/mp4", - "video/quicktime" -]New value: +[ + "image/jpeg", + "image/png", + "image/webp", + "video/mp4", + "video/quicktime", + "application/pdf", + "application/vnd.ms-powerpoint", + "application/vnd.openxmlformats-officedocument.presentationml.presentation", + "application/msword", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document" +]
- Changed
update_post3 fields changed- changed
Input schema / properties / contentType / descriptionPrevious value: -"New content type; must match the media on the post"New value: +"New content type; must match the media on the post. DOCUMENT publishes one PDF, PPT, PPTX, DOC or DOCX file (max 100 MB, 300 pages) as a LinkedIn document post and is LinkedIn only: put exactly that one file in mediaUrls, target only LINKEDIN, and set the title with linkedinConfigs" - changed
Input schema / properties / contentType / enumPrevious value: -[ - "TEXT", - "IMAGE", - "VIDEO", - "CAROUSEL" -]New value: +[ + "TEXT", + "IMAGE", + "VIDEO", + "CAROUSEL", + "DOCUMENT" +] - added
Input schema / properties / linkedinConfigsAdded value: +{ + "description": "LinkedIn per-connection config: documentTitle names a DOCUMENT post. connectionId must match an entry in linkedinConnectionIds", + "items": { + "additionalProperties": false, + "properties": { + "connectionId": { + "description": "LinkedIn connection ID from list_accounts", + "type": "string" + }, + "documentTitle": { + "description": "Title LinkedIn shows on a DOCUMENT post (max 100 chars). Defaults to the file name; ignored for other content types", + "maxLength": 100, + "type": "string" + } + }, + "required": [ + "connectionId" + ], + "type": "object" + }, + "type": "array" +}
- Changed
upload_media4 fields changed- changed
Input schema / properties / files / descriptionPrevious value: -"Direct file uploads as base64, 30 MB decoded per call in total. Use this when the user attaches/pastes an image or video in the conversation"New value: +"Direct file uploads as base64, 30 MB decoded per call in total. Use this when the user attaches/pastes an image, video or document in the conversation" - changed
Input schema / properties / files / items / properties / fileName / descriptionPrevious value: -"File name with extension (e.g. \"photo.jpg\")"New value: +"File name with extension (e.g. \"photo.jpg\" or \"deck.pptx\")" - changed
Input schema / properties / files / items / properties / mimeType / enumPrevious value: -[ - "image/jpeg", - "image/png", - "image/webp", - "video/mp4", - "video/quicktime" -]New value: +[ + "image/jpeg", + "image/png", + "image/webp", + "video/mp4", + "video/quicktime", + "application/pdf", + "application/vnd.ms-powerpoint", + "application/vnd.openxmlformats-officedocument.presentationml.presentation", + "application/msword", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document" +] - changed
Input schema / properties / urls / descriptionPrevious value: -"Public https URLs of images or videos to upload (e.g. [\"https://example.com/photo.jpg\"])"New value: +"Public https URLs of images, videos or documents to upload (e.g. [\"https://example.com/photo.jpg\", \"https://example.com/deck.pdf\"])"
Related MCP Connectors
Post and schedule to Instagram, TikTok, YouTube, LinkedIn, X, Threads, Bluesky, Pinterest, Facebook.
Publish and analyze posts on Instagram, Facebook, TikTok, YouTube, X, and Bluesky.
Post, schedule, reply and measure across X, LinkedIn, Instagram, TikTok, YouTube, Threads, Bluesky
Schedule posts to Instagram, TikTok, LinkedIn, X and 6 more. Track analytics and reply to comments.
Related MCP Servers
AlicenseAqualityBmaintenanceSchedule, publish, and measure social posts on Facebook, Instagram, TikTok, LinkedIn, Threads, Pinterest, and X for one brand or many.34MIT- AlicenseAqualityDmaintenanceAI-powered social media posting across 14 platforms. Post to Twitter, Instagram, TikTok, Facebook, LinkedIn, YouTube and more with one command. AI adapts content per platform, schedules posts, and generates 30-day content calendars.6MIT
- AlicenseAqualityBmaintenanceSchedule, manage, generate, and analyze social posts across 11 networks (Instagram, TikTok, X, LinkedIn, YouTube, Facebook, Pinterest, Threads, Bluesky, Mastodon, Telegram) from any AI agent — 13 tools covering scheduling, media upload, AI caption generation, best-times, analytics, listening, and comments.1349 npmMIT
- AlicenseNot gradedqualityCmaintenanceManage Threads and Bluesky social media from AI assistants. Schedule posts, check analytics, and automate follow-up replies.3MIT
Glama MCP Gateway
Add one secure layer between your agents and this server.