Install
openclaw skills install @orshot/orshot-social-media-schedulerSocial media scheduler and social media automation for AI agents. Schedule posts, post to Instagram, post to LinkedIn, post to X (Twitter), TikTok, Facebook, Pinterest, Threads, Bluesky, Reddit, YouTube, Telegram, Snapchat and Google Business with Orshot, with the image, carousel or video rendered from a template in the same call. Use to schedule a social post, run a weekly content calendar, cross-post to every platform, queue drafts for review, read post analytics and follower growth, find the best time to post, or build an agent that posts and learns. Everything runs over the hosted Orshot MCP server (OAuth, no key); REST with an API key for headless jobs.
openclaw skills install @orshot/orshot-social-media-schedulerOrshot renders an image, carousel or video from a template and posts it to 13+ platforms in one request. It also holds drafts, schedules, edits and reports analytics, so an agent can run a whole content calendar without a second tool. Posts can also attach any public media URL, so it works with images made elsewhere.
Platforms: X (Twitter), Instagram, Facebook, LinkedIn (profile and page), TikTok, YouTube, Pinterest, Reddit, Bluesky, Threads, Telegram, Snapchat, Google Business.
Nothing works before this. The MCP route has no key to paste, shows every post as a visual card, and is the one to use from an agent.
openclaw mcp add orshot --url https://mcp.orshot.com/mcp --transport streamable-http --auth oauth
openclaw mcp login orshot
Claude Code: claude mcp add --transport http orshot https://mcp.orshot.com/mcp. Other MCP clients take the same URL.
Headless jobs only (cron, n8n, a server script): export ORSHOT_API_KEY=... and call REST with Authorization: Bearer $ORSHOT_API_KEY.
orshot_list_social_accounts # MCP
GET /v1/social/accounts?include_health=true # REST
# [{ "id": 1, "platform": "linkedin", "account_name": "Acme", "account_username": "acme", "health": { "status": "ok" } }]
A list with accounts means you can post. Note the numeric id of each one and any health flag that says reconnect.
An empty list means a human still has to connect accounts. The API cannot connect one. Send the user to their Orshot dashboard: Workspace > Socials > Accounts (https://orshot.com/dashboard, then the Socials section of the workspace), where each platform connects with its own OAuth login. Social publishing is an add-on on paid plans, $12 per connected account per month, with no extra credits per post; the free plan cannot connect accounts. Plans and the add-on are on https://orshot.com/pricing. Say this once, plainly, and wait for the user to come back; the next orshot_list_social_accounts call will show the new account.
templateId + modifications) or use an existing media_url.status: "draft" unless the user clearly said to post now.orshot_get_social_post renders a visual card.orshot_update_social_post), then publish (orshot_publish_social_draft) or schedule (status: "scheduled" + scheduled_for).processing becomes published or failed.| Job | Tool |
|---|---|
| list accounts | orshot_list_social_accounts |
| render + post in one call | orshot_render_template with publish |
| post a media URL | orshot_publish_social_post |
| list / read posts | orshot_list_social_posts, orshot_get_social_post (visual card) |
| edit / send / discard | orshot_update_social_post, orshot_publish_social_draft, orshot_discard_social_post |
| analytics | orshot_get_social_analytics, orshot_get_social_analytics_daily, orshot_get_social_followers, orshot_get_social_post_analytics |
| best time to post | orshot_get_best_time_to_post |
The MCP server defaults to status: "draft" short of an explicit go-ahead. Keep it that way.
Over MCP this is orshot_render_template with the same publish object.
await fetch("https://api.orshot.com/v1/studio/render", {
method: "POST",
headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
body: JSON.stringify({
templateId: 123,
modifications: { headline: "Ship day", stat: "2,000 renders" },
response: { type: "url", format: "png" },
publish: {
accounts: [1, 3],
content: "Caption up to 5000 chars",
status: "scheduled", // published | draft | scheduled
scheduled_for: "2026-11-01T14:00:00Z",
timezone: "America/New_York",
platformOptions: {
"3": { firstComment: "https://orshot.com", disableLinkPreview: true }, // LinkedIn
},
},
}),
});
Multi-page templates publish as a carousel on platforms that support it. The response has data.content (the render) and publish[] with one entry per account.
orshot_publish_social_post, or:
curl -s -X POST https://api.orshot.com/v1/social/publish \
-H "Authorization: Bearer $ORSHOT_API_KEY" -H "Content-Type: application/json" \
-d '{
"accounts": [2],
"content": "Six things nobody tells you",
"media_urls": ["https://.../1.png", "https://.../2.png", "https://.../3.png"],
"status": "draft",
"tiktokSettings": { "autoAddMusic": true }
}'
| Field | Notes |
|---|---|
accounts | required, numeric ids |
content | caption, max 5000 chars |
media_url / media_urls | one or many public URLs; many = carousel |
status | published (default over REST), draft, scheduled |
scheduled_for | ISO 8601, at least 60 s ahead, only with scheduled |
timezone | IANA name |
platformOptions | per account id: LinkedIn firstComment, disableLinkPreview; Pinterest title, link |
tiktokSettings.autoAddMusic | root level, TikTok photo carousels |
Response: { post_id, status, platforms: [{ account_id, platform, status, url, error, action }] }. status can be published, scheduled, drafted, partial, processing or failed. action: "reconnect" means the human must reconnect that account in the dashboard.
GET /v1/social/posts?status=draft&limit=25 # also scheduled | published | processing | partial | failed, platform=, account_id=, cursor=
GET /v1/social/posts/:id
PATCH /v1/social/posts/:id # content, media_urls, accounts, status (draft|scheduled), scheduled_for, timezone, platformOptions
POST /v1/social/posts/:id/publish # send a held post now
POST /v1/social/posts/:id/sync # refresh provider status
DELETE /v1/social/posts/:id # discard; refused once any account went live
is_editable and is_discardable on each post tell you what is still allowed. Editing never re-renders and costs nothing.
GET /v1/social/analytics?platform=linkedin&source=orshot # per post: impressions, engagement, clicks, rate; followers per account
GET /v1/social/analytics/daily?from=2026-10-01&to=2026-10-21 # day by day
GET /v1/social/analytics/accounts?from=2026-09-01 # follower history and growth per account
GET /v1/social/analytics/insights?platform=instagram # best day-and-hour slots (UTC), frequency vs engagement, decay
source is all, orshot or external (posts synced from the platform, so history exists from day one). refresh=1 bypasses the cache. Budget: 10 analytics requests per minute. Insights need posting history, so a new account returns empty slots.
Render seven posts from one template with different modifications, create each with status: "draft", list them for the user with orshot_list_social_posts, publish or schedule the approved ones. One update per change of caption or time.
orshot_get_best_time_to_post for the platform, take the top slot (UTC), convert to the user's timezone, pass it as scheduled_for. If slots are empty, ask the user for a time rather than inventing one.
One accounts array with all ids. Put the link in platformOptions[<linkedin id>].firstComment, a title and link for Pinterest, and tiktokSettings.autoAddMusic for TikTok photo posts. Keep content under the shortest limit of the platforms you target (X is the tightest).
Render a 5 to 10 page template with pageN@ keys and add publish. Orshot uploads every page and posts a carousel on Instagram, LinkedIn, TikTok (photo mode), Threads and Bluesky. The orshot-carousel skill has the 6-slide formula.
Daily: orshot_get_social_analytics with source: "orshot", sort by engagement, keep the hook styles of the top quarter, drop the bottom quarter, write the next week's drafts. Record what changed so the user can read the log.
partial or failed with action: "reconnect": tell the user which account to reconnect in the dashboard (Workspace > Socials > Accounts), keep the post as a draft, retry with orshot_publish_social_draft after they confirm. Any other error: show it verbatim; do not retry blindly.
status: "draft".png, jpg or webp (or mp4 for video platforms).scheduled_for under 60 seconds ahead is rejected, and it is invalid with draft or published.processing is not a failure. Sync or re-read the post before reporting.publish[] even when the render succeeded./social/* with a plan message is a billing state, not an auth bug. Point to https://orshot.com/pricing.openclaw mcp add orshot --url https://mcp.orshot.com/mcp --transport streamable-http --auth oauth && openclaw mcp login orshot
GET /v1/social/accounts?include_health=true # orshot_list_social_accounts
POST /v1/studio/render # + publish: { accounts, content, status, scheduled_for, timezone, platformOptions, tiktokSettings } orshot_render_template
POST /v1/social/publish # { accounts, content, media_url | media_urls, status, scheduled_for, timezone, platformOptions, tiktokSettings } orshot_publish_social_post
GET /v1/social/posts?status=draft # orshot_list_social_posts
GET /v1/social/posts/:id # orshot_get_social_post
PATCH /v1/social/posts/:id # orshot_update_social_post
POST /v1/social/posts/:id/publish # orshot_publish_social_draft
POST /v1/social/posts/:id/sync
DELETE /v1/social/posts/:id # orshot_discard_social_post
GET /v1/social/analytics # orshot_get_social_analytics
GET /v1/social/analytics/daily?from=&to= # orshot_get_social_analytics_daily
GET /v1/social/analytics/accounts?from= # orshot_get_social_followers
GET /v1/social/analytics/insights?platform= # orshot_get_best_time_to_post
Docs: https://orshot.com/docs/publish/introduction.md, https://orshot.com/docs/api-reference/social-publish.md, https://orshot.com/docs/api-reference/social-posts-list.md. Rendering details live in the orshot skill.