
Postproxy
dev.postproxy由 postproxy.dev 發布官方發布者v1.10.0更新於 Oct 24, 2026
Publish, schedule, and manage social media posts across major platforms via the Postproxy API.
概覽
透過 Postproxy API 在各大社群平台發佈、排程與管理貼文,並處理留言與私訊。
- 可以做什麼
- 發佈、排程或存成草稿,投遞到已連結的社群帳號,支援各平台專屬參數與佇列時段
- 查詢貼文狀態、刪除貼文,讀取貼文與帳號的互動數據趨勢
- 列出帳號群組、帳號與刊登位置,並為新帳號啟動連結授權流程
- 讀取、發表、回覆、編輯、隱藏、按讚與刪除已發佈貼文的留言
- 列出會話與訊息、建立會話,並在 Facebook、Instagram、Telegram、Bluesky 與 WhatsApp 上傳送私訊
- 管理發佈佇列並檢視最近的發佈任務紀錄
- 適用情境
- 適合讓助理端到端處理社群媒體營運:撰寫與排程內容、確認貼文是否送出、取得互動數據,以及處理留言和私訊,不必在多個工具間切換。
- 執行需求
- 遠端端點 mcp.postproxy.dev(streamable HTTP),或在本機使用 postproxy-mcp npm 套件。需要 Postproxy 帳號與 API 金鑰,透過 X-PostProxy-API-Key 標頭或 POSTPROXY_API_KEY 環境變數提供;也可改用支援動態用戶端註冊的 OAuth。社群帳號須先經 Postproxy 的 OAuth 流程連結。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 Postproxy,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Web executable,透過 Streamable HTTP。 遠端服務在工作區中設定後即可從網頁執行環境執行。
交給代理程式安裝
把這段提示詞貼上到 Claude Code、Codex、Cursor 等代理程式,或 SourceWeft 對話中。代理程式會讀取該伺服器的安裝指南,先向你展示發布者、端點和登入方式,經你同意後再把它新增到你的客戶端。金鑰不會寫進任何命令。
閱讀 https://sourceweft.com/mcp/dev.postproxy%2Fpostproxy/install.md,並按其中說明把這個 MCP 伺服器接入我的客戶端。修改任何設定之前,先告訴我它的發布者、端點和登入方式,等我確認。不要把 API 金鑰寫進命令或我會提交的檔案;問我金鑰應從哪裡取得。其他 MCP 客戶端
把它新增到你客戶端的 mcpServers 設定中。
{
"mcpServers": {
"postproxy": {
"type": "http",
"url": "https://mcp.postproxy.dev/mcp"
}
}
}README
Postproxy MCP Server
MCP (Model Context Protocol) server for integrating Postproxy API with Claude Code. This server provides tools for publishing posts, checking statuses, and managing social media profiles through Claude Code.
Installation
Global Installation
Local Installation
Claude Code stores MCP server configuration under ~/.claude/plugins/.
After installing postproxy-mcp, Claude will automatically detect the server on restart.
Configuration
Register MCP Server
After installing postproxy-mcp, register it with Claude Code using the claude mcp add command:
Replace your-api-key with your actual Postproxy API key.
The configuration will be automatically saved to ~/.claude/plugins/. After running this command:
- Restart your Claude Code session
- Test the connection by asking Claude: "Check my Postproxy authentication status"
- If tools are available, Claude will be able to use them automatically
Alternative: Interactive Setup
For non-technical users, you can use the interactive setup command:
or
This will guide you through the setup process step by step and register the server using claude mcp add automatically.
Available Tools
Authentication Tools
auth_status
Check authentication status, API configuration, and workspace information.
Parameters: None
Returns:
Account Overview
summary_get
Answer "what's the status?" in one call — an activity snapshot for a time window instead of separate history_list / comments_list / dm_chats_list round trips.
Parameters:
window(string, optional):24h(default),7d, or30dfrom(string, optional): ISO 8601 timestamp or bare date starting an explicit range. Overrideswindow, and the*_previouscounts come backnullto(string, optional): End of the explicit range. Defaults to now when onlyfromis givenprofile_group_id(string, optional): Report on a single group. Omit to cover every group the key can reach
Returns:
Notes:
- Post counts are posts, so a post sent to three networks counts once and a thread counts once.
by_platformcounts per-network deliveries, so a 3-item X thread is 3 undertwitter. engagementis lifetime-to-date for posts published in the window, not engagement earned during it — it sums each post's newest stats snapshot. A post published minutes ago may have no snapshot yet and won't be inposts_with_insights. Keys are the normalized metrics listed in Stats Fields by Platform.- The
awaiting_replycounts describe current state, not the window — they don't change when you changewindow. They look back 30 days, returned aswindow.backlog_from. A comment counts as replied only when the reply came from you (via Postproxy or the profile itself);chats_awaiting_replyis derived from message timestamps, since Postproxy has no read/unread state. reply_window_closingcounts chats with under 6 hours of their 24h messaging window left. Networks without a window (Telegram, Bluesky) are excluded.engagementisnullwhen insights are off for the account;dmsisnullwhen DMs are off.- Scoped like every other tool: a group-scoped key reports only its group.
Profile Management
profile_groups_list
List all profile groups accessible with your API key. Profile groups are organizational containers (e.g. per brand or client) that hold related profiles. Use a group's id to filter profiles_list by profile_group_id.
Parameters: None
Returns:
profile_groups_initialize_connection
Generate a connect URL for a new profile in a profile group. The user opens the URL to finish the OAuth flow.
Parameters:
profile_group_id(string, required): Profile group IDplatform(string, required): Platform to connect (e.g.instagram,linkedin,whatsapp)onboarding(string, optional): Instagram and WhatsApp only. Instagram:instagram(default) uses Instagram Login;facebookuses Facebook Login, for an Instagram professional account linked to a Facebook Page you manage. The profile isplatform: "instagram"either way, and reconnecting with the other method updates the existing profile in place. WhatsApp:apiorbusiness_app(see WhatsApp Business Management).identifier+app_password(Bluesky) /bot_token(Telegram): credentials, local server only
profiles_list
List all available social media profiles for posting.
Parameters:
profile_group_id(string, optional): If provided, only profiles in this group are returned (useprofile_groups_listto find group IDs)
Returns:
profiles_placements
List available placements for a profile. For Facebook profiles, placements are business pages. For LinkedIn profiles, placements include the personal profile and organizations. For Pinterest profiles, placements are boards. For Telegram profiles, placements are channels the bot can post to. For Google Business profiles, placements are locations, returned as full resource paths (accounts/X/locations/Y) to pass as location_id. For WhatsApp profiles, placements are the phone numbers on the Business Account — the placement id is the phone_number_id every whatsapp_* tool and dm_chat_create take. Available for facebook, linkedin, pinterest, telegram, google_business, and whatsapp profiles.
Parameters:
profile_id(string, required): Profile hashid
Returns (LinkedIn example):
Notes:
- If no placement is specified when creating a post:
- LinkedIn: defaults to the personal profile
- Facebook: defaults to a random connected page (if only one page is connected, no need to set a placement ID)
- Pinterest: it fails
- Telegram: it fails —
chat_idis required on every post - Google Business: it fails —
location_idis required on every post and on everygoogle_business_*tool
profiles_stats
Get the follower/engagement timeseries for a profile. Snapshots are captured roughly every 23 hours, so you can plot follower growth and other trends over time. The stats fields are platform-native (not normalized) — see Stats Fields by Platform in the post_stats section for shape and add-on profile-level keys (followers_count, followersCount, etc.) per network.
Parameters:
profile_id(string, required): Profile hashidplacement_id(string, conditional): Required forfacebook,linkedin,telegram, andgoogle_businessprofiles. Get it fromprofiles_placements. Omit forinstagram,threads,youtube,twitter,tiktok,pinterest, andbluesky.from(string, optional): ISO 8601 timestamp — only include snapshots recorded at or after this timeto(string, optional): ISO 8601 timestamp — only include snapshots recorded at or before this time
Returns (LinkedIn example):
For non-placement networks (e.g. Bluesky), omit placement_id:
Post Management
post_publish
Publish a post to specified social media profiles.
Parameters:
-
content(string, required): Post content text -
profiles(string[], required): Array of profile IDs (hashids) or platform names (e.g.,"linkedin","instagram","twitter"). When using platform names, posts to the first connected profile for that platform. -
schedule(string, optional): ISO 8601 scheduled time -
media(string[], optional): Array of media URLs or local file paths -
idempotency_key(string, optional): Idempotency key for deduplication -
require_confirmation(boolean, optional): If true, return summary without publishing -
draft(boolean, optional): If true, creates a draft post that won't publish automatically -
queue_id(string, optional): Queue ID to add the post to. The queue will automatically assign a timeslot. Do not use together withschedule. -
queue_priority(string, optional): Priority when adding to a queue:high,medium(default), orlow -
platforms(object, optional): Platform-specific parameters. Key is platform name (e.g., "instagram", "youtube", "tiktok"), value is object with platform-specific options. See Platform Parameters Reference for full documentation.Example:
Returns:
Note on draft posts: If you request a draft post (draft: true) but the API returns draft: false, a warning field will be included in the response indicating that the API may have ignored the draft parameter. This can happen if the API does not support drafts with certain parameters (e.g., media attachments) or under specific conditions. Check the warning field in the response for details.
post_status
Get status of a published post by job ID.
Parameters:
post_id(string, required): Post ID from post.publish response
Returns:
scheduled_at is null for posts published immediately. Platform url is the published permalink (null until published).
Status values:
overall_status:"draft","pending","processing","complete","failed"- Platform
status:"pending","processing","published","failed","deleted" - Platform
error: Error message if publishing failed (null if successful)
post_publish_draft
Publish a draft post. Only posts with draft: true status can be published using this endpoint.
Parameters:
post_id(string, required): Post ID of the draft post to publish
Returns:
post_delete
Delete a post by job ID.
Parameters:
post_id(string, required): Post ID to delete
Returns:
post_stats
Get stats snapshots for one or more posts. Returns all matching snapshots so you can see trends over time. Supports filtering by profiles/networks and timespan.
Parameters:
post_ids(string[], required): Array of post hashids (max 50)profiles(string, optional): Comma-separated list of profile hashids or network names (e.g.instagram,twitterorabc123,def456or mixed)from(string, optional): ISO 8601 timestamp — only include snapshots recorded at or after this timeto(string, optional): ISO 8601 timestamp — only include snapshots recorded at or before this time
Returns:
Stats fields by platform:
Notes: Instagram stories do not return stats. TikTok stats require the post to have a public ID.
Queue Management
queues_list
List all posting queues. Queues automatically schedule posts into recurring weekly timeslots with priority-based ordering.
Parameters:
profile_group_id(string, optional): Filter queues by profile group
Returns:
queues_get
Get details of a single posting queue including its timeslots and post count.
Parameters:
queue_id(string, required): Queue ID
queues_create
Create a new posting queue with weekly timeslots.
Parameters:
profile_group_id(string, required): Profile group ID to connect the queue to (useprofiles_listto find this)name(string, required): Queue namedescription(string, optional): Optional descriptiontimezone(string, optional): IANA timezone name (e.g.America/New_York). Default:UTCjitter(number, optional): Random offset in minutes (0–60) applied to scheduled times for natural posting patterns. Default:0timeslots(array, optional): Initial weekly timeslots. Each object hasday(0=Sunday through 6=Saturday) andtime(24-hourHH:MMformat)
Example:
queues_update
Update a queue's settings, timeslots, or pause/unpause it. Changes to timezone or timeslots trigger rearrangement of all queued posts.
Parameters:
queue_id(string, required): Queue ID to updatename(string, optional): New queue namedescription(string, optional): New descriptiontimezone(string, optional): IANA timezone nameenabled(boolean, optional): Set tofalseto pause the queue,trueto unpausejitter(number, optional): Random offset in minutes (0–60)timeslots(array, optional): Timeslots to add or remove. To add:{ "day": 1, "time": "09:00" }. To remove:{ "id": 42, "_destroy": true }.
queues_delete
Delete a posting queue. Posts in the queue will have their queue reference removed but will not be deleted.
Parameters:
queue_id(string, required): Queue ID to delete
queues_next_slot
Get the next available timeslot for a queue.
Parameters:
queue_id(string, required): Queue ID
Returns:
Adding Posts to a Queue
When publishing a post with post_publish, you can add it to a queue instead of scheduling it manually:
queue_id(string, optional): Queue ID to add the post to. The queue will automatically assign a timeslot. Do not use together withschedule.queue_priority(string, optional): Priority level:high,medium(default), orlow. Higher priority posts get earlier timeslots.
Example:
Comment Management
comments_list
List comments on a published post. Returns paginated top-level comments with nested replies.
Parameters:
post_id(string, required): Post IDprofile_id(string, required): Profile ID to identify which platform's comments to retrievepage(number, optional): Page number, zero-indexed (default: 0)per_page(number, optional): Number of top-level comments per page (default: 20)from(string, optional): ISO 8601 date/time — only comments received at or after this pointto(string, optional): ISO 8601 date/time — only comments received at or before this point
from/to filter on when Postproxy received the comment, not the platform's posted_at (which isn't always populated). A bare date such as 2026-03-25 means that date's start of day. The filter applies to top-level comments only — a comment in range still returns its full replies array.
Returns:
Comment objects may also include an attachments array (media on the comment — image, video, audio, gif, external, file), each with id, type, url, status, and external_id. Populated for Facebook, Threads, and Bluesky; Instagram, YouTube, and LinkedIn comments are text-only. The array is empty when there is no media.
comments_get
Get a single comment with its replies.
Parameters:
post_id(string, required): Post IDcomment_id(string, required): Comment ID (Postproxy ID or platform external ID)profile_id(string, required): Profile ID
comments_create
Create a comment or reply on a published post. The comment is published to the platform asynchronously.
Parameters:
post_id(string, required): Post IDprofile_id(string, required): Profile IDtext(string, required): Comment text contentparent_id(string, optional): ID of comment to reply to (Postproxy ID or external ID). Omit to comment on the post itself.
Returns:
The comment is created with status: "pending". Once published to the platform, it becomes "published". If publishing fails, it becomes "failed".
comments_delete
Delete a comment from the platform asynchronously. Supported on Instagram, Facebook, YouTube, and LinkedIn. Not supported on Threads.
Parameters:
post_id(string, required): Post IDcomment_id(string, required): Comment ID (Postproxy ID or external ID)profile_id(string, required): Profile ID
comments_edit
Edit the text of a comment you published, asynchronously. Supported on Facebook and YouTube only. Returns { accepted: true }; the outcome arrives via comment.edited / comment.edit_failed webhooks.
Parameters:
post_id(string, required): Post IDcomment_id(string, required): Comment ID (Postproxy ID or external ID)profile_id(string, required): Profile IDbody(string, required): New comment text
comments_hide
Hide a comment on the platform asynchronously. Supported on Instagram, Facebook, and Threads.
Parameters:
post_id(string, required): Post IDcomment_id(string, required): Comment IDprofile_id(string, required): Profile ID
comments_unhide
Unhide a previously hidden comment. Supported on Instagram, Facebook, and Threads.
Parameters:
post_id(string, required): Post IDcomment_id(string, required): Comment IDprofile_id(string, required): Profile ID
comments_like
Like a comment on the platform asynchronously. Currently only supported on Facebook.
Parameters:
post_id(string, required): Post IDcomment_id(string, required): Comment IDprofile_id(string, required): Profile ID
comments_unlike
Remove a like from a comment. Currently only supported on Facebook.
Parameters:
post_id(string, required): Post IDcomment_id(string, required): Comment IDprofile_id(string, required): Profile ID
Platform Support
Direct Messages
1:1 messaging (chats and messages) on DM-capable profiles. Supported on Facebook (Messenger), Instagram (DMs), Telegram (Bot DMs), Bluesky, and WhatsApp. Outbound sends are processed asynchronously (returned with status: "pending"). Meta's 24h messaging window applies to Facebook/Instagram — a human replying to the participant's own inquiry can pass tag: "HUMAN_AGENT" to send outside it (up to 7 days, never for promotional or automated content); Telegram and Bluesky have no window. On WhatsApp the window is re-opened only by sending an approved template (template) or a category: "utility" text — see WhatsApp Business Management for the rest of the WhatsApp surface.
dm_chats_list
List chats for a profile, ordered by most recent activity.
Parameters:
profile_id(string, required): Profile ID (Facebook, Instagram, Telegram, Bluesky, or WhatsApp)page(number, optional): Page number, zero-indexed (default: 0)per_page(number, optional): Items per page (default: 20)before/after(string, optional): ISO 8601 timestamp filters onlast_message_at
WhatsApp chats also carry external_placement_id (the phone number the chat belongs to), group (true for group chats) and within_messaging_window.
dm_chat_create
Find or create a chat for a participant (idempotent — returns the existing chat if one exists). Use before messaging a participant the profile hasn't messaged yet.
Parameters:
profile_id(string, required): Profile IDparticipant_external_id(string, required): Platform participant ID (IG-scoped user ID, Facebook PSID, Telegram user id, Bluesky DID, or a WhatsApp phone number with country code — non-digits are stripped)placement_id(string, optional): Placement id fromprofiles_placements. Required on WhatsApp (the phone number the chat is on); optional on Facebook (page id)participant_username(string, optional)participant_name(string, optional)
A brand-new WhatsApp conversation has no open messaging window, so the first send into it must be a template (see dm_message_send).
dm_chat_get
Get a single chat by Postproxy ID or platform external_conversation_id.
Parameters:
chat_id(string, required): Chat ID or external conversation ID
dm_messages_list
List messages in a chat, most recent first.
Parameters:
chat_id(string, required): Chat ID or external conversation IDpage(number, optional): Page number, zero-indexed (default: 0)per_page(number, optional): Items per page (default: 20)direction(string, optional):inboundoroutboundstatus(string, optional): Filter by message status
dm_message_send
Send an outbound message. Provide exactly one of body (text), media (a single attachment), or — on WhatsApp — template, interactive, location or contacts.
Parameters:
chat_id(string, required): Chat ID or external conversation IDbody(string, optional): Message text (required when nothing else is sent; on WhatsApp it may also accompanymediaas the caption)media(string[], optional): Up to one attachment as a URL or local file path. Not supported on Bluesky. (The remote/Worker MCP accepts URLs only.) WhatsApp limits: image 5MB jpeg/png, video 16MB mp4/3gpp, audio 16MB, document 100MB.tag(string, optional):HUMAN_AGENTto send outside the 24h window — extends it to 7 days from the participant's last inbound message (Facebook/Instagram only). Meta restricts it to a human replying to the participant's own inquiry; using it for marketing, offers, or automated re-engagement can get that Page / Instagram account's messaging capability suspended. Past 7 days Meta rejects the send and the message lands instatus: failedwith the platform error inerror_details.reply_to_external_id(string, optional): Telegram, WhatsApp & Instagram — platform message id (Telegrammessage_id, WhatsAppwamid, Instagrammid) to quote / thread underreply_markup(object, optional): Telegram only — inline/reply keyboard payloadquick_replies(object[], optional): Facebook & Instagram only — up to 13 tappable chips above the participant's composer. Each{ title, payload }.buttons(object[], optional): Facebook & Instagram only — up to 3 buttons attached to the message. Each{ type: "web_url", title, url }or{ type: "postback", title, payload }.card(object, optional): Facebook & Instagram only — extra fields for the card carryingbuttons(subtitle,image_url,default_action). Requiresbuttons.template(object, optional): WhatsApp only — send an approved template:{ id | name, language, variables[], button_params[], header_media, header_location }. The only way to message outside the 24h window or to open a new conversation.interactive(object, optional): WhatsApp only — Meta-shaped interactive message (reply buttons, list, cta_url, product, flow, location request), passed through unchangedlocation(object, optional): WhatsApp only —{ latitude, longitude, name, address }contacts(object[], optional): WhatsApp only — contact cards in Meta'scontactsshapecategory(string, optional): WhatsApp only —"utility"marks a plain text send as a utility Direct Send that may go outside the window without a templatelink_preview(boolean, optional): WhatsApp only —falsesuppresses the URL preview on a text messagevoice_note(boolean, optional): WhatsApp only — deliver an OGG/Opus audio attachment as a voice notefilename(string, optional): WhatsApp only — display name for a document attachment
Quick replies and buttons
Facebook Messenger and Instagram Direct only — on Telegram use reply_markup instead (passing these returns a 422). Quick replies are ephemeral chips that vanish once one is tapped; buttons stay attached to the message in the thread.
Buttons are delivered as a Meta generic template whose element title is your body — that's where the 80-character cap comes from. Instagram is stricter than Messenger: it delivers quick replies only on a plain-text message, so quick_replies with media or with buttons returns 422 there.
Receiving taps: a tapped chip or button postback arrives as an inbound message carrying tapped_action: { "kind": "quick_reply" | "postback" | "callback_query", "payload": "...", "title": "..." }. Read it from dm_messages_list / dm_message_get instead of digging through platform_data. Instagram ice-breaker taps and Telegram callback queries normalize to the same field.
WhatsApp templates and interactive messages
A WhatsApp number can only send free-form text, media, interactive, location and contacts while the participant's 24h window is open (within_messaging_window on the chat). Outside it — including a conversation you start yourself — send an approved template. variables fill the placeholders in order (header text vars first, then body vars, then dynamic URL button vars) and must match the template's variable_count from whatsapp_templates_list; the rendered body is stored on the message.
Templates with a media header take header_media: { "link": "https://..." }; a location header takes header_location; URL / copy-code / flow buttons take button_params: [{ "index": 0, "sub_type": "url", "parameters": [{ "type": "text", "text": "12345" }] }].
Inside the window, interactive is Meta's own object — reply buttons (up to 3), a list (up to 10 rows), a CTA URL, a product card, a flow or a location request:
A tap comes back as an inbound message whose body is the tapped title, with the reply id under platform_data.interactive. Facebook/Instagram quick_replies / buttons return 422 on WhatsApp, and template / interactive / location / contacts / category return 422 on every other network.
dm_message_get
Get a single message by Postproxy ID or platform external_id.
Parameters:
message_id(string, required): Message ID or external ID
dm_message_edit
Edit a previously-sent outbound message. Telegram only. Provide body and/or reply_markup (pass {} to clear the keyboard); at least one is required.
Parameters:
message_id(string, required): Message ID or external IDbody(string, optional): New text/captionreply_markup(object, optional): New keyboard (or{}to remove)
dm_message_react / dm_message_unreact
Add or remove your business account's reaction on a message. Facebook Messenger, Instagram Direct and WhatsApp.
Parameters (dm_message_react):
message_id(string, required): Message ID or external IDreaction(string, optional): Named reaction (defaultlove). Ignored on WhatsAppemoji(string, optional): Unicode emoji. Required on WhatsApp (any emoji)
Parameters (dm_message_unreact):
message_id(string, required)
dm_chat_archive / dm_chat_unarchive
Archive (mute) or unarchive (unmute) a chat. Bluesky only. Returns the chat with archived set.
Parameters:
chat_id(string, required): Chat ID or external conversation ID
dm_chat_mark_read
Mark a chat as read. On WhatsApp this sends the read receipt (blue ticks) for the newest inbound message; on other networks it only stamps metadata.read_at. Returns the chat.
Parameters:
chat_id(string, required): Chat ID or external conversation ID
dm_comment_private_reply
Send a DM to the author of a comment, in reply to that comment (Meta "Private Replies"). Bypasses the 24h window (comments up to 7 days old) and creates/reuses a chat automatically. One private reply per comment, ever. Instagram and Facebook only.
Parameters:
post_id(string, required): Post IDcomment_id(string, required): Comment ID or external IDprofile_id(string, required): Profile ID (Instagram or Facebook)text(string, required): DM textquick_replies(array, optional): Up to 13 chips — same shape asdm_message_sendbuttons(array, optional): Up to 3 buttons — same shape asdm_message_send; capstextat 80 characterscard(object, optional): Card styling forbuttons(subtitle,image_url,default_action)
Interactive elements follow the same rules as dm_message_send — on Instagram, quick_replies and buttons are mutually exclusive. Media attachments are not available on private replies.
Thread control (Facebook & Instagram)
Meta lets several apps share a Page's or Instagram account's inbox (Postproxy, Meta's inbox, chatbots like ManyChat), but only one controls a conversation at a time. Messages still reach Postproxy while another app holds it, but sends are rejected until control comes back.
Each takes chat_id and an optional metadata note forwarded to the receiving app. The four control actions return the chat with metadata.thread_control refreshed.
Platform Support
History
history_list
List recent post jobs.
Parameters:
limit(number, optional): Maximum number of jobs to return (default: 10)
Returns:
scheduled_at is null for posts that were published immediately. status is the raw API status (draft, scheduled, processing, processed, …), while overall_status folds platform outcomes into a single verdict.
Note: Postproxy's
/postsAPI does not return profile identity (profile ID or name) per platform — only the network. Useprofiles_listto map networks to connected profiles.
Google Business Profile Management
These edit the Google business listing itself — hours, attributes, services, food menus, action links and profile photos — as opposed to publishing local posts to it (that's post_publish with platform google_business).
Three rules apply to every tool in this group:
location_idis always required. It's the full Google resource pathaccounts/X/locations/Y, returned byprofiles_placements.- Updates are field-masked. Each write takes a
fieldsarray naming exactly what's being replaced. Anything named infieldsbut absent from the payload is cleared, and nested objects are replaced wholesale rather than merged. Always read before you patch. - Availability varies by category and region. Attributes, service lists, food menus and action link types differ per listing. List what's available first; a location that isn't eligible returns
422.
Payloads use Google's own shapes and camelCased keys in both directions, so a response can be sent straight back as a request body.
Typical flow
Attribute value shapes
google_business_attributes_available returns a valueType per attribute, which decides the shape to send back:
attribute_mask defaults to exactly the names you send, so a partial update never clears attributes you left out.
Hours
Times accept either "09:00" / "09:00:00" strings or Google's { "hours": 9, "minutes": 0 } objects — both are normalized before the call. Read current hours from google_business_location_get; each block named in fields is replaced entirely.
Media
Google downloads the file from media_url itself — there is no upload step, so the URL must be publicly reachable https (not a short-lived signed URL, not localhost). Images need at least 250×250 and at most 5MB. category defaults to ADDITIONAL; use COVER or LOGO only when you intend to change the profile header or logo.
Reading empty results
Google omits keys rather than returning empty values: a listing with no attributes returns { "name": "..." } with no attributes key at all, and the same applies to serviceItems, placeActionLinks and boolean flags like isPreferred. Treat absent as empty.
Analytics
Google Business location analytics come through the standard profiles_stats tool — pass the location_id as placement_id. Metrics are Search and Maps impressions (desktop and mobile), website clicks, call clicks, direction requests, conversations, bookings, food orders and food-menu clicks. Google Business has no follower count, and Google exposes no per-post analytics for local posts. For the search terms people used to find the location, use google_business_search_keywords.
WhatsApp Business Management
Manage a connected WhatsApp Business Account beyond the inbox: message templates, phone-number status and registration, the public business profile, display name and username, blocked users, groups, and Click-to-WhatsApp conversion reporting. Conversations themselves go through the dm_* tools above.
Four rules apply to every tool in this group:
- The WhatsApp Business Account (WABA) is the profile; each phone number on it is a placement. Phone-scoped tools take
phone_number_id— the placementidfromprofiles_placements(its metadata carriesdisplay_phone_number,quality_rating,messaging_limit_tier,name_status,platform_type). - Templates and the Conversions dataset are WABA-level — those tools take only
profile_id. - Free-form messages only inside the 24h window. Once a participant's last inbound message is older than 24h (or the conversation is new),
dm_message_sendaccepts only an APPROVEDtemplate(or acategory: "utility"text). A delivered template re-opens the window. - Coexistence numbers are limited. A number connected with
onboarding: "business_app"(still in the WhatsApp Business app on a phone) has lower throughput and cannot use the Groups API;whatsapp_number_inforeportsplatform_typeother thanCLOUD_APIfor these.
Responses use Meta's own field names where Meta's shapes are returned (components, interactive, business profile fields).
Typical flow
Connecting a number
profile_groups_initialize_connection with platform: "whatsapp" returns a connect URL. Pass onboarding: "business_app" when the number lives in the WhatsApp Business app on a phone (the user scans a QR code; the app keeps working alongside Postproxy and up to 6 months of chats are imported) or onboarding: "api" when the number is with another provider or brand new (moved onto the Cloud API; no longer usable in the app). Omit it and the connect page asks. Each WhatsApp Business Account becomes one profile and each of its numbers a placement.
Templates
Meta reviews every custom template; a new one is PENDING until approved, and only APPROVED templates can be sent. Placeholders are {{1}}, {{2}}… (parameter_format: POSITIONAL, the default) or {{name}} (NAMED). variable_count on a template is the number of variables a send must carry: header text placeholders, then body placeholders, then one per dynamic-URL button. Library templates (whatsapp_template_library_get → whatsapp_template_create with library_template_name) skip review. A name is unique per language; deleting by name without language removes every language.
Conversions
Conversations that start from a Click-to-WhatsApp ad carry a ctwa_clid on the chat's metadata. Create a dataset once (whatsapp_dataset_create), then report outcomes with whatsapp_conversion_event_send by chat_id or phone; a chat with no captured ctwa_clid returns 422.
Example Prompts
Here are some example prompts you can use with Claude Code:
Check Authentication
List Profiles
Publish a Post
Using profile IDs:
Using platform names:
Instagram Reel Audio and Collaboration Invites
These only work for Instagram profiles connected through Facebook Login (profile_groups_initialize_connection with onboarding: "facebook"); Instagram Login profiles return 422.
Pinterest Boards
YouTube Playlists
Pass a playlist's id as platforms.youtube.playlist_id in post_publish to add the uploaded video to it. Create/update/delete cost 50 YouTube API quota units each.
Publish with Platform Parameters
You can use platform-specific parameters to customize posts for each platform. The platforms parameter accepts an object where keys are platform names and values contain platform-specific options.
Instagram Examples
Regular Post with Collaborators:
Or with explicit parameters:
Instagram Reel:
Instagram Reel with Library Music (Facebook Login profiles; get audio_id from instagram_available_audio):
audio_volume / video_volume take 1–100 (default 100). strip_audio removes the video's own sound (reels and video stories) and works on any Instagram profile.
Instagram Story:
YouTube Examples
YouTube Video with Title and Privacy:
Or with explicit parameters:
Unlisted YouTube Video:
TikTok Examples
Public TikTok with Auto Music:
TikTok for Followers Only with AI Label:
Facebook Examples
Facebook Post with First Comment:
Facebook Story:
Facebook Page Post:
LinkedIn Examples
Personal LinkedIn Post:
Company LinkedIn Post:
Bluesky Examples
Plain Bluesky post (auto-faceted mentions/tags/links):
You don't need any markup — Postproxy auto-converts @handles, #tags, and URLs into AT Protocol facets, and generates a link card preview from the URL's Open Graph meta (when no media is attached). 300-grapheme limit.
Telegram Examples
Telegram channel post (HTML formatting):
Use profiles_placements against your Telegram profile to list channel chat_ids the bot can post to. The bot must be added to the channel as administrator with permission to post.
Cross-Platform Examples
Same Content, Different Platforms:
Video Across Platforms with Specific Parameters:
Platform Parameters Reference
Instagram:
format: "post" | "reel" | "story"collaborators: Array of usernames (max 10 for posts, 3 for reels)first_comment: String - comment to add after postingcover_url: String - thumbnail URL for reelsaudio_name: String - audio track name for reelstrial_strategy: "MANUAL" | "SS_PERFORMANCE" - trial strategy for reelsthumb_offset: String - thumbnail offset in milliseconds for reelsalt_text: String or array (matching media order) - image alt text, max 1,000 charsshare_to_feed: Boolean - reels only;falsepublishes to the Reels tab only (default shares to the feed/grid)disable_comment: Boolean - turn comments off right after publishing (posts, reels)location_id: String - numeric ID of a Facebook Page with an address to tag as the location (posts, reels; not stories)user_tags: Array of{ username, x, y, media_index }- tag public Instagram accounts on any format (post, reel, story). Images requirexandy(floats0.0–1.0from the top-left corner); reels and video slides are tagged by username only (coordinates are dropped); stories accept coordinates but don't need them.media_indexpicks the carousel slide (0-based, default0). A leading@is stripped. Out-of-range coordinates, amedia_indexpast the last media item, or an image tag missingx/yare rejected with a 422 naming the entry. Private accounts and accounts with tagging off are silently skipped by Instagram.
YouTube:
title: String - video titleprivacy_status: "public" | "unlisted" | "private"cover_url: String - custom thumbnail URLplaylist_id: String - add the video to this playlist (fromyoutube_playlists_list)
TikTok:
privacy_status: "PUBLIC_TO_EVERYONE" | "MUTUAL_FOLLOW_FRIENDS" | "FOLLOWER_OF_CREATOR" | "SELF_ONLY"photo_cover_index: Integer - index of photo to use as cover (0-based)auto_add_music: Boolean - enable automatic musicmade_with_ai: Boolean - mark content as AI-generateddisable_comment: Boolean - disable commentsdisable_duet: Boolean - disable duetsdisable_stitch: Boolean - disable stitchesbrand_content_toggle: Boolean - mark as paid partnership (third-party)brand_organic_toggle: Boolean - mark as paid partnership (own brand)upload_as_draft: Boolean - send to the creator's TikTok inbox instead of publishingthumb_offset: String - video cover frame in milliseconds
Facebook:
format: "post" | "story"first_comment: String - comment to add after postingpage_id: String - page ID for posting to company pageslink: String - URL shared as a link post with preview card (text-only)alt_text: String or array - image alt textmade_with_ai: Boolean - AI disclosure (photo posts only)countries: Array or comma-separated string - ISO country codes to restrict viewers to
LinkedIn:
format: "post" | "poll"organization_id: String - organization ID for company page postsreshare_urn: String - reshare an existing LinkedIn postalt_text: String or array - image alt textcountries: Array or comma-separated string - country targeting (organization posts only, up to 25)poll_question/poll_options/poll_duration_days: poll format — question 1-140 chars, 2-4 options of ≤30 chars, duration 1/3/7/14 daysdocument_title: String - title shown above an attached document (defaults to the file name)first_comment: String - comment posted right after publishing as the same author (max 1,250 chars; profiles connected on/after 2026-10-28)
Pinterest:
board_id: String - board placement fromprofiles_placements(create one withpinterest_board_create)title: String - pin title, max 100 charsdestination_link: String - URL the pin links tocover_url: String - cover image for video pinsthumb_offset: Integer - video thumbnail offset in secondsalt_text: String - image pin alt text
Telegram:
chat_id: String, required — destination channel/chat ID (useprofiles_placementsto list)parse_mode: "HTML" | "MarkdownV2" — omit for plain textdisable_link_preview: Boolean — suppress URL preview carddisable_notification: Boolean — send silently (no notification sound)- Character limit: 4,096 for text-only; 1,024 for the caption when media is attached (body beyond is truncated)
- Media: images ≤10 MB (×10), video ≤50 MB (×10), documents ≤50 MB (×1)
- The bot must be a member (preferably administrator with post permission) of the destination channel
Bluesky:
alt_text: String or array - image alt text- Character limit: 300 graphemes (emoji and combining sequences count as one)
- Auto-detects
@handle.bsky.socialmentions,#hashtags, and URLs and converts them to clickable facets - Generates a link card preview from Open Graph meta when a URL is present and no media is attached
- Media: images ≤1 MB (×4), video ≤100 MB (×1, 1–60s)
- Supports threads via the standard
threadarray
Twitter/X:
format: "post" | "poll"alt_text: String or array - image alt text, max 1,000 charspoll_options/poll_duration_minutes: poll format — 2-4 options of ≤25 chars, 5-10080 minutes
Threads:
alt_text: String or array - image alt texttopic_tag: String - one topic tag without#, max 50 chars, no periods or ampersands
For complete documentation, see the Platform Parameters Reference.
Create a Draft Post
Publish a Draft Post
Check Post Status
This will show detailed status including draft status, platform-specific errors, and publishing results.
Delete a Post
Get Post Stats
List Placements
Queue Management
Comment Management
Direct Messages
WhatsApp Business Management
View History
Troubleshooting
Server Won't Start
- Check API Key: Ensure
POSTPROXY_API_KEYis set when registering withclaude mcp add - Check Node Version: Requires Node.js >= 18.0.0
- Check Installation: Verify
postproxy-mcpis installed and in PATH - Check Registration: Ensure the server is registered via
claude mcp addand configuration is saved in~/.claude/plugins/
Authentication Errors
- AUTH_MISSING: API key is not configured. Make sure you included
--env POSTPROXY_API_KEY=...when runningclaude mcp add - AUTH_INVALID: API key is invalid. Verify your API key is correct.
Validation Errors
- TARGET_NOT_FOUND: One or more profile IDs don't exist. Use
profiles_listto see available profiles. - VALIDATION_ERROR: Post content or parameters are invalid. The API now returns detailed error messages:
- 400 errors:
{"status":400,"error":"Bad Request","message":"..."} - 422 errors:
{"errors": ["Error 1", "Error 2"]}- Array of validation error messages - Check the error message for specific validation issues
- 400 errors:
API Errors
- API_ERROR: Postproxy API returned an error. Check the error message for details.
- Timeout: Request took longer than 30 seconds. Check your network connection and API status.
Platform Errors
When checking post status with post_status, platform-specific errors are now available in the error field of each platform object:
error: null- Post published successfullyerror: "Error message"- Detailed error message from the platform API- Common errors include authentication issues, rate limits, content violations, etc.
Draft Post Issues
If you create a draft post (draft: true) but receive draft: false in the response:
- The response will include a
warningfield explaining that the API may have ignored the draft parameter - This can happen if:
- The API does not support drafts with media attachments
- The API has specific limitations for draft posts under certain conditions
- Check the
warningfield in the response for details - Enable debug mode (
POSTPROXY_MCP_DEBUG=1) to see detailed logging about draft parameter handling
Debug Mode
Enable debug logging by setting POSTPROXY_MCP_DEBUG=1 when registering the server:
Development
Building from Source
Running in Development Mode
License
MIT
來源:README.md,提交 9ad8f44
工具
0版本歷史
1- v1.10.0最新Sep 16, 2026
評分
已滿足適用檢查項的 85%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通必需25 分
- 已宣告認證方式必需10 分
- 已列出工具必需15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分