MCPOutils MCP/Publications
Publications
Créer, publier et analyser des publications sociales, y compris les publications sponsorisées.
- Writecreate_postCreate a post for a location (or client) and submit it to the selected platforms — name them in `platforms`, or name exact accounts in `connectionIds` (from list_publish_targets) and omit `platforms`. One of the two is required. When it has destinations, the response also carries `targets`: each connection's platform and status. Publishes immediately unless scheduledFor is set or draft is true. A requested platform with no active connection never fails this call — the post is still created (as a draft if nothing resolved), and the response is `{ status: "no_connection", missingPlatforms, scope, post: { id, status } }` instead of the usual `{ id, status }` for whichever platforms couldn't resolve a connection. Compose what to tell the user from that data; do not assume the call failed just because `status` is "no_connection" — the content was saved. Likewise a post that cannot go live yet because a REQUIRED FIELD is absent (an event with no start/end date, a caption-less announcement, Instagram with no image) is saved as a draft and answers `{ status: "incomplete", missingFields, scope, post }`. Both gaps can appear together, in which case `status` is "no_connection" and `missingFields` rides alongside it — tell the user about BOTH at once rather than letting them discover the second after fixing the first. In every one of these cases the content EXISTS as a draft: say what was saved, name what it needs, point at where to fix it, and never report it as a failure. PLATFORM RULES (enforced — violations rejected): Post types: `announcement` works on every platform; `event` and `offer` are Google-only (any social platform ⇒ must be announcement). Caption char limits: google 1500, facebook 30000, instagram 2200, x 280 WEIGHTED characters rather than typed ones — Japanese/Chinese/Korean characters and emoji cost 2 each and any link costs a flat 23, so a non-Latin caption fits roughly 140 typed characters; setting linkUrl appends that link to the caption for a further 25 weighted (X thread mode is exempt from the limit entirely), linkedin 2000, pinterest 500, mastodon 500, bluesky 300, youtube 5000. Media (per platform, using each item's `platform`): facebook ≤10 images OR ≤1 video, no mix (carousel = 2–10 images only, per-card headline ≤80 / description ≤200); instagram requires ≥1 media, ≤10 images OR ≤1 video, no image/video mix; x ≤4 images OR ≤1 video, no mix; linkedin ≤5 images OR ≤1 video, no mix; pinterest image-only, exactly 1, required; mastodon ≤4 images OR ≤1 video, no mix; youtube video-only, exactly 1, required. Google event ⇒ eventTitle (≤58 chars) + eventStartAt + eventEndAt (end after start) required. Google offer ⇒ ctaType + ctaUrl required. scheduledFor must be in the future. Drafts (draft=true) skip required-field checks but still enforce all structural checks above.
- Writeupdate_postUpdate an editable post (draft/scheduled/error/active). Only the content and schedule fields you supply are changed — omitted fields keep their stored values (name, postType, platforms, captions, media, scheduledFor, etc.). Editing a post that is a draft keeps it a draft — a caption fix never publishes it. To take a draft live pass draft=false, a scheduledFor, or call publish_post_now. Pass draft=true to save any post as a draft (skips required-field checks); on a post that is already scheduled/active, omitting draft reconciles and publishes. Reconciles platform submissions. UI Series drafts use suggestedFor rather than an applied schedule; read get_distribution_campaign and preview_distribution_time_change first. Generic update_post does not authorize Series scheduling. A requested platform with no active connection never fails this call either (same as create_post) and the response is `{ status: "no_connection", missingPlatforms, scope, post: { id, status } }` instead of the usual `{ id, status }`. PLATFORM RULES (enforced — violations rejected): Post types: `announcement` works on every platform; `event` and `offer` are Google-only (any social platform ⇒ must be announcement). Caption char limits: google 1500, facebook 30000, instagram 2200, x 280 WEIGHTED characters rather than typed ones — Japanese/Chinese/Korean characters and emoji cost 2 each and any link costs a flat 23, so a non-Latin caption fits roughly 140 typed characters; setting linkUrl appends that link to the caption for a further 25 weighted (X thread mode is exempt from the limit entirely), linkedin 2000, pinterest 500, mastodon 500, bluesky 300, youtube 5000. Media (per platform, using each item's `platform`): facebook ≤10 images OR ≤1 video, no mix (carousel = 2–10 images only, per-card headline ≤80 / description ≤200); instagram requires ≥1 media, ≤10 images OR ≤1 video, no image/video mix; x ≤4 images OR ≤1 video, no mix; linkedin ≤5 images OR ≤1 video, no mix; pinterest image-only, exactly 1, required; mastodon ≤4 images OR ≤1 video, no mix; youtube video-only, exactly 1, required. Google event ⇒ eventTitle (≤58 chars) + eventStartAt + eventEndAt (end after start) required. Google offer ⇒ ctaType + ctaUrl required. scheduledFor must be in the future. Drafts (draft=true) skip required-field checks but still enforce all structural checks above.
- Readget_postGet a post with per-platform submission performance (agency-scoped).
- Readlist_publish_targetsList where a post for this location can go: its own connected profiles and its client's brand-level pages. Each target's connectionId is what create_post / update_post take in `connectionIds` to publish to exactly those. canPublish is false when the connection needs reconnecting. Same list as GET /api/v1/locations/{id}/publish-targets.
- Readlist_postsScope location means one location, brand means locationless client posts, all means every client post; default location when locationId is given, otherwise all. List real Posts, including unpublished Series drafts and client-level posts without a location. Provide clientId or locationId; both must agree. Follow nextPage until hasMore is false and reconcile changed totals/IDs; pages are live, not a snapshot. createdFrom/createdTo (legacy from/to) filter creation dates; scheduledFrom/scheduledTo filter actual schedules, never suggestions. UI Series titles belong to list_distribution_campaigns, not ContentSeries ideas.
- Writedelete_postDelete a post and unpublish it from its platforms. Unpublishes every platform first, then archives the post ONLY IF every platform unpublish succeeded — this never permanently deletes the row; it just stops appearing anywhere in the API. If even one platform fails to unpublish, nothing is archived — the call still succeeds (no throw) but returns `ok: false` with a `failed` list; check `ok` rather than assuming the post is gone.
- Writepublish_post_nowPublish an EXISTING POST now: force-submit a draft/errored post (retries pending/errored platform submissions). To publish an idea use publish_post_idea instead. Throws if the post is scheduled for a future time — cancel or wait for the schedule instead. A no-op (no error, nothing retried) if there's nothing pending or errored to retry.
- Readget_post_analyticsPost analytics rollup for a client: engagement summary, per-platform breakdown, trends, top posts. Use for social media performance, content effectiveness. channel `brand` (default) is the client's brand-level pages; `local` is its locations' own profiles, optionally narrowed to the locations carrying one tag (a name from list_location_tags). The result says which slice it covers (`scope`). Brand and local are separate numbers — add them yourself if you want a combined figure, and note a page can appear in only one. Pass postId (a published YouTube video) to get that video's YouTube Analytics report instead — the post page's analytics panel — filtered by `report` (daily, totals, retention, traffic, searches, geography, demographics, devices, subscribers, content, revenue; default daily) and from/to (YYYY-MM-DD, required with postId).
- Readget_posts_client_rollupPosts summary across all locations: total posts, per-location post health, which locations fall behind on posting cadence. Use for social media overview, content output review.
- Writecreate_post_boostBoost a post with paid ad spend through a connected ad account — this spends real money. dailyBudget (minor currency units, e.g. cents) and durationDays are ALWAYS required, regardless of whether you also pass boostConfigId; if boostConfigId is given, only its adAccountId/targeting/publisherPlatforms/delayHours are used as defaults for whatever you don't specify — its own saved budget is never used silently. Pass postSubmissionId to boost an ALREADY-PUBLISHED post's live submission (spends immediately). Pass postId (+ platform or connectionId) instead to pre-configure a boost on a post that hasn't published yet — it stays queued (no spend) and only starts once that post's submission goes live. adAccountId must belong to a connected account (see list_ad_accounts); use select_ad_account first if none is selected.
- Readlist_post_boostsList boosts (paid promotions of posts), newest first, so one can be found again without the create_post_boost response: status, whether it is deferred (waiting for its post to publish), the budget, spend so far, the post it promotes, and `control` — the tool that applies now (`stop_post_boost` with adRunId for a live one, `cancel_deferred_boost` with adCampaignId for a deferred one, null when it is over). Filter by postId, status, or activeOnly. Up to 50 per page; follow hasMore. A client (portal) session sees only its own client's boosts, without the agency's ad spend and without controls; a member limited to some clients sees only those clients'.
- Readget_post_boostGet one boost by its adRunId (from list_post_boosts or create_post_boost): status, budget, spend, the post, and the control that applies. A client (portal) session can read only its own client's boosts, without spend or controls.
- Writestop_post_boostStop a LIVE boost that's already spending on the platform — halts real in-flight ad spend. This cannot be resumed; a new boost would need to be created. To cancel a boost that hasn't gone live yet (still queued, awaiting the post to publish, no spend yet), use cancel_deferred_boost instead. Identify the boost by its adRunId — find it with list_post_boosts (each boost lists the control that applies).
- Writecancel_deferred_boostCancel a deferred boost that hasn't gone live yet (its post hasn't published, so no money has been spent). To stop a boost that's already live and spending, use stop_post_boost instead. Identify it by its adCampaignId — find it with list_post_boosts (a deferred boost shows its adCampaignId). Answers `{ cancelled: true, runsCancelled }` when it cancelled something, `{ cancelled: false, reason }` when the boost exists but nothing was waiting, and an error when the id is not a boost of this agency.
- Writecreate_youtube_playlistCreate a playlist on a connected YouTube channel (the composer's "New playlist"). Returns its id and title, to put a video in when publishing. Title up to 150 characters; privacy private | public | unlisted.
- Readget_post_boost_analyticsRead paid-promotion totals, trends and per-post performance for one client, with brand/local channel and optional local tag filters. Requires an active agency user with Social and owning-client access. Reads stored results only and never publishes or creates ad spend. Date filters, where supported, default to the last 30 days.
- Readget_post_follower_analyticsRead follower snapshots, measured coverage and prior-window comparisons for client brand accounts. Missing observations remain unavailable. Requires an active agency user with Social and owning-client access. Reads stored results only and never publishes or creates ad spend. Date filters, where supported, default to the last 30 days.
- Readget_location_post_analyticsRead Google and Facebook local post views, clicks, daily trends and top posts for a location. Requires an active agency user with Social and owning-client access. Reads stored results only and never publishes or creates ad spend. Date filters, where supported, default to the last 30 days.
- Readget_post_boost_campaignsRead all campaigns behind one post, including budget, targeting, status and latest recorded performance. Returns a distinct campaign count. Requires an active agency user with Social and owning-client access. Reads stored results only and never publishes or creates ad spend. Date filters, where supported, default to the last 30 days.
- Writepause_scheduled_postPause a scheduled post while retaining its date and destinations. A post already claimed for publishing is refused. Requires the Social revamp feature and an active agency user with Social and owning-client access.
- Writeresume_paused_postResume a paused post at its existing future date. Past dates are refused. Series publishing permissions, approvals and paused/archived series checks still apply. Requires Social revamp and an active agency user with Social and owning-client access.
- Writeunschedule_postMove a scheduled post back to draft, clear its date and disarm failed-submission retries. Preserves its destinations. Refuses cancellation once publishing has claimed the post. Requires an active agency user with Social and owning-client access.
- Writeduplicate_postCopy a post through the ordinary creation and content-check pipeline. Optional scheduledFor is an ISO timestamp; omitted date or draft:true saves a draft. Series variants cannot be duplicated this way. Requires Social revamp and an active agency user with Social and owning-client access. Never authorizes bypassing content checks.
- Writerecord_assisted_post_outcomeRecord an assisted publication the user already completed outside Synup. action:published requires its live URL matching the destination; Reddit also requires rulesReviewed:true only when the person explicitly confirmed reviewing the destination rules. action:emailed records a Substack email already sent after web publication. Never publishes or sends email itself. Refuses canceled submissions and archived series. Requires an active agency user with Social and owning-client access.