Social Media Action
One node, every supported social platform. Picks the platform from a registry and dispatches universal operations (post, reply, repost, like, search, …) plus platform-specific extras. Use the crosspost sentinel to fan out to multiple platforms in one node, or pair with the Trigger node to listen for new posts across platforms in a single trigger.
Supported providers
| Platform | Credential | Auth model | Notes |
|---|---|---|---|
| Bluesky | bluesky_app_password | App password | No platform-side review. Cardyb-backed link card embeds for richer posts. |
| X (Twitter) | twitter_oauth2 | OAuth 2.0 + PKCE | 280-weighted-char cap with smart-truncate / auto-thread escape hatches (see below). |
| Mastodon | mastodon_oauth2 | OAuth 2.0 (per-instance app reg) | Per-instance app registered dynamically on first connect. 500-char cap. |
linkedin_oauth2 | OAuth 2.0 (UGC API) | Personal posts only in V1. postWithMedia + searchPosts gated. | |
| Threads | threads_oauth2 | Meta Graph + long-lived token | Two-step token (short → long-lived 60d). Daily refresh cron. Single + carousel media (10 max). |
instagram_oauth2 | Facebook Login + IG Graph | Business / Creator account linked to a FB Page. 2200-char captions. Single + carousel up to 10 (image + video). All posts require media — no text-only. | |
| Facebook Pages | facebook_oauth2 | Facebook Login + Page tokens | Posts to a Page you administer (V1 picks first page). Text + single image; multi-image albums + video deferred. |
developers.facebook.com/apps covers both platforms. Add products: Facebook Login for Business + Instagram Graph API. Set env vars META_OAUTH_CLIENT_ID + META_OAUTH_CLIENT_SECRET. Add valid OAuth redirect URIs: {API_URL}/api/credentials/instagram/oauth/callback + {API_URL}/api/credentials/facebook/oauth/callback.Operation gates
Most universal operations work on every provider. A few are gated by the platform itself — either behind a paid partnership tier or behind a scope that needs review by the platform's team. The provider throws a clear error when you try to run a gated op so the AI Toolkit and the canvas surface the gate without a silent failure.
searchPosts
Recent-search requires special access on LinkedIn and Threads. The other three providers (Bluesky, X, Mastodon) ship it under their regular auth.
| Platform | searchPosts | What unlocks it |
|---|---|---|
| Bluesky | Available | Public AT-Protocol search. |
| X (Twitter) | Available | Free tier ≈ 100 reads/day. Basic ($200/mo) lifts the cap. Hit /2/tweets/search/recent internally. |
| Mastodon | Available | Per-instance search via the standard API. |
| Gated | Requires LinkedIn Marketing Developer Platform (MDP) partnership. Apply at linkedin.com/developers. Approval can take weeks to months and is granted to verified marketing/analytics use cases — not casual integrations. | |
| Threads | Gated | Requires the threads_keyword_search scope, which is a premium scope under Meta review. Only granted for approved business / research use cases. Apply via the Threads / Meta App Review flow. |
| Gated | Hashtag search via /ig_hashtag_search needs additional Meta App Review + heavy rate-limit gates. Mentions surface is Webhooks-only push, not pull — different shape entirely. Both deferred until customer demand. | |
| Facebook Pages | Gated | Page-graph search needs Pages Public Content Access permission, which goes through Meta App Review for any non-developer use. Mentions same gate. |
searchPosts on a gated platform without the partnership, the provider throws an explicit error explaining what to apply for — not a silent empty result.postWithMedia
All five providers ship media uploads. Per-platform notes:
- Bluesky — up to 4 images, 1 MB each, blob upload at post time.
- X (Twitter) — up to 4 images, 5 MB each, single-shot upload via
/2/media/upload. - Mastodon — up to 4 attachments via the per-instance
/api/v2/mediawebhook. - LinkedIn — IMAGE only in V1, up to 9 images per UGC post, 5 MB each. Uses the 3-step
registerUploaddance (register → PUT binary → reference asset URN in the UGC post). VIDEO support deferred — throws a clear early error when a video URL is detected so users aren't left waiting on a confusing LinkedIn rejection. - Threads — async container + publish flow with status polling. Single image/video, or CAROUSEL up to 10 mixed image/video children.
- Instagram — same container + publish flow as Threads. Single image/video or CAROUSEL (10 mixed). All posts require media; no text-only. 2200-char captions.
- Facebook Pages — V1 ships text + single image only. Multi-image albums (
create-then-publishdance) + video (chunked resumable upload) deferred to a follow-up.
X (Twitter) long-text strategies
X enforces a 280-weighted-character cap on Free / Basic / Pro tiers (URLs count as 23 after t.co shortening; emoji as 2). The default rejects posts that exceed the cap at validation time. Switch the “When text exceeds 280 chars” selector under any text-posting op (postText, replyToPost, quoteTweet, postWithMedia) to opt into one of two escape hatches:
- Smart truncate — trims your text at the last word boundary, appends an ellipsis, and (if you set
truncateAppendUrl) reserves room for a permalink at the end. URL is counted as 23 weighted chars regardless of its raw length, so even a 200-char URL only steals 23 from your budget. - Auto-thread — splits the text into a chain of replies, posting each ≤ 280-weighted chunk via
in_reply_to_tweet_id. Cuts on paragraph (\n\n) → sentence (. ! ?) → word boundaries in that priority order. WiththreadNumbering(default ON) each chunk gets a(i/N)suffix so readers see the order. The lead tweet's id surfaces at the top of the output (postId,url) for back-compat; the full chain lives inposts[]with_meta.iterable: truefor downstream loops.
{
"platform": "twitter",
"postedAt": "2026-05-10T14:23:11.582Z",
"postId": "1791000000000000001", // lead tweet
"url": "https://x.com/i/status/1791000000000000001",
"text": "First chunk … (1/3)",
"threadCount": 3,
"_meta": { "iterable": true, "iterateField": "posts", "count": 3 },
"posts": [
{ "threadIndex": 1, "postId": "1791000000000000001", "url": "...", "text": "First chunk … (1/3)" },
{ "threadIndex": 2, "postId": "1791000000000000002", "url": "...", "text": "Second chunk … (2/3)" },
{ "threadIndex": 3, "postId": "1791000000000000003", "url": "...", "text": "Third chunk (3/3)" }
]
}postWithMedia + auto-thread, media attaches to the first tweet only — subsequent reply chunks are text-only. Matches what readers expect when scrolling a thread on X.Related
- Crosspost — set
platform: "crosspost"and supply acredentialIdsmap +operationConfig.targetPlatforms[]to fan out a single text/media post to N platforms in parallel. Each result lands inoutput.results[]with per-platformsuccess+errorfields so downstream nodes can iterate. - Trigger — to listen for new posts across multiple platforms (Bluesky, X, Mastodon today) in a single trigger, see the multi-platform poll configuration.