Social media API
One API for every feed your agent posts to.
Connect an account once, then publish with a single request. X, Bluesky, LinkedIn, Mastodon and Telegram are live today. Every response says which accounts published, which are retrying, and why.
The short answer · Updated Nov 1, 2026
A social media API lets software publish posts to social networks without a person pressing "post". A unified social media API like SocialsForAI wraps each network's own API (X API v2, LinkedIn's Posts API, Bluesky's AT Protocol) behind one endpoint, one connect flow for account owners and one error format, so an app or AI agent writes one integration instead of one per network.
| Network | Text limit | Images | Fair-use cap per account | Status |
|---|---|---|---|---|
| Bluesky | 300 graphemes | 4, up to 2 MB each | 300 posts / 24h | Live |
| X | 280 weighted characters (URLs count 23) | 4, up to 5 MB each | 100 posts / 24h | Live |
| 3,000 characters | Up to 20, up to 20 MB each | 50 posts / 24h | Live, personal profiles only | |
| Mastodon | 500 characters (URLs count 23), any server | 4, up to 16 MB each | 300 posts / 24h | Live |
| Telegram | 4,096 characters; 1,024 as a caption with images | Up to 10, up to 10 MB each | 500 posts / 24h | Live, channels and groups via your bot |
Limits are the ones our preflight enforces (src/providers). Platform limits come from each network's docs, read 2026-11-01. Video isn't supported on any network yet.
What does one API call do?
One POST /v1/posts checks the post against every target network's limits, publishes to each account in parallel, reads the post back where the network allows it, and returns one receipt. You send text, optional media URLs and a list of account ids.
The checks run before anything leaves our servers: length (weighted for X, graphemes for Bluesky), image count, empty posts, the same text on the same account in the last 24 hours, and per-account fair-use caps. They are plain code with no AI calls, so a dry_run: true request costs nothing and posts nothing.
Send an Idempotency-Key header. If your request times out and you retry with the same key and body, you get the original post back with Idempotent-Replayed: true instead of a second post. The same key with a different body returns 409 idempotency_key_reused.
curl https://socialsforai.com/v1/posts \
-H "Authorization: Bearer $SOCIALS_API_KEY" \
-H "Idempotency-Key: launch-0412" \
-d '{
"accounts": ["acc_bluesky", "acc_linkedin", "acc_x"],
"text": "We just shipped webhooks.",
"wait": true
}'What does the response look like?
Every post has one target per account, and each target carries its own status, URL, attempt count and error. The post's overall status is published, partially_published, failed, scheduled, publishing or canceled, derived from its targets.
In the response below, Bluesky published and was verified by reading the post back. LinkedIn failed because its 60-day token expired; the error says so and says what to do. With wait: true the call returns after delivery; without it you get 201 straight away and a post.published, post.partially_published or post.failed webhook later.
HTTP/1.1 201 Created (trimmed: media, metadata, target ids and some target fields omitted)
{
"id": "post_9fQ2mXc4LpZr8TwA",
"object": "post",
"status": "partially_published",
"text": "We just shipped webhooks.",
"scheduled_at": null,
"created_at": "2026-11-01T15:04:05.000Z",
"completed_at": "2026-11-01T15:04:07.000Z",
"targets": [
{
"account_id": "acc_bluesky",
"platform": "bluesky",
"status": "published",
"url": "https://bsky.app/profile/acme.bsky.social/post/3m4xq7k2c2s2a",
"attempts": 1,
"verified": true,
"error": null
},
{
"account_id": "acc_linkedin",
"platform": "linkedin",
"status": "failed",
"url": null,
"attempts": 1,
"verified": false,
"error": {
"code": "account_needs_reauth",
"message": "LinkedIn access token expired (they last 60 days).",
"fix": "Reconnect the LinkedIn account with a new connect link.",
"retryable": false
}
}
]
}What errors come back, and how do you fix them?
Errors that we can predict come back before publishing as a 422 preflight_failed, listing every issue with the account, the field and a fix sentence. Nothing is published when any account fails preflight, so you never get half a launch because one network's text was too long.
Errors from the network itself land on the target. Retryable ones (platform_rate_limited, platform_unavailable, media_fetch_failed on a 5xx) retry after 30 seconds, 2 minutes, 10 minutes, 30 minutes and 2 hours, six attempts in all, then the target becomes failed. Permanent ones stop at once.
text_too_long: shorten it, or setplatform_options.x.text(or.bluesky,.linkedin) to a per-network version.too_many_media: X and Bluesky take 4 images, LinkedIn 20.duplicate_content: same text, same account, last 24 hours. Vary it or wait.daily_cap_reached: schedule it withscheduled_atinstead.account_needs_reauth: send the owner a new connect link; anaccount.needs_reauthwebhook fires when this happens.video_not_supported: video isn't built on any network yet.plan_limit_active_accountsandplan_limit_posts: Free plan limits (3 active accounts, 100 posts a month).
HTTP/1.1 422 Unprocessable Entity
{
"error": {
"code": "preflight_failed",
"message": "The post would fail on 1 check(s). Nothing was published.",
"fix": "Fix the issues below, or send dry_run: true to iterate without publishing.",
"issues": [
{
"account_id": "acc_x",
"platform": "x",
"severity": "error",
"code": "text_too_long",
"field": "platform_options.x.text",
"message": "Text is 312 characters; X allows 280.",
"fix": "Shorten it by 32+ characters, or set platform_options.x.text to a shorter version."
}
]
}
}Should you use a network's own API or a unified API?
Use the network's own API when you post to one network, from accounts you control, and need features a unified layer doesn't expose. That is a real and common case, and the first-party route is cheaper and has fewer moving parts.
Use a unified API when you post to two or more networks, or post for other people. Posting for other people is where first-party work grows: each network wants its own developer app, its own review (LinkedIn's Community Management API, Meta's App Review, TikTok's audit) and its own token refresh rules.
- Go first-party for one Bluesky bot. The AT Protocol has no app review and no fee; our Bluesky API guide shows the raw calls.
- Go first-party for LinkedIn Company Pages, X polls or quote posts, video, analytics, DMs or reading timelines. We don't do those yet.
- Go unified when an AI agent posts. Structured
codeandfixfields, idempotency keys and an MCP server save you writing that layer. - Go unified when end users connect their own accounts and you don't want to hold their tokens or build reconnect flows.
How do accounts get connected?
The account owner opens a hosted connect link: OAuth for X and LinkedIn, an app password for Bluesky, the server URL and an access token for Mastodon, and a bot token plus channel or group for Telegram. You never see their password, and stored credentials are encrypted with AES-256-GCM and deleted on disconnect.
Tag the link with external_ref (your client id or user id) and every account it creates carries it. Links expire after 7 days by default, configurable from 5 minutes to 30 days. Set redirect_url and the owner lands back in your app with account_id, platform and status=connected in the query string.
curl https://socialsforai.com/v1/connect-links \
-H "Authorization: Bearer $SOCIALS_API_KEY" \
-d '{
"platforms": ["bluesky", "linkedin"],
"external_ref": "client_42",
"redirect_url": "https://yourapp.example/connected"
}'
# 201 → { "id": "cl_...", "object": "connect_link", "url": "...", "expires_at": "..." }Can an AI agent use the API directly?
Yes. The same operations are exposed as an MCP server over Streamable HTTP at /api/mcp, with tools for listing platforms and accounts, creating connect links, creating, reading and canceling posts, and checking usage. create_post waits for delivery by default so the agent sees the result in the same turn.
An agent can even get its own key: POST /v1/workspaces returns a Free-plan API key without a browser. Setup for Claude Code is one command.
claude mcp add --transport http socials https://socialsforai.com/api/mcp \
--header "Authorization: Bearer $SOCIALS_API_KEY"From zero to a published post
- 01
Get a key
POST /v1/workspaces returns a Free-plan API key. Store it; it isn't shown again. Agents can do this step themselves.
- 02
Send a connect link
POST /v1/connect-links returns a URL. The account owner opens it, approves access, and the account appears in GET /v1/accounts.
- 03
Dry-run the post
POST /v1/posts with dry_run set to true returns every issue with a fix and a per-account preview of the text, and publishes nothing.
- 04
Publish
Send it for real with wait set to true and an Idempotency-Key header. Retrying with the same key never posts twice.
- 05
Listen for webhooks
Register an endpoint with POST /v1/webhooks. Payloads are signed with HMAC-SHA256 in the Socials-Signature header, and failed deliveries retry on a schedule from 1 minute to 24 hours.
Questions
What developers ask
What is the best social media API for developers?
It depends on the networks and who owns the accounts. For one network and your own account, that network's API is simplest. For several networks, or for accounts your users own, a unified API saves building OAuth, token refresh and error handling per network. Compare pricing models too: per profile, per channel or per active account.
Which networks can I post to with SocialsForAI?
X, Bluesky, LinkedIn personal profiles, Mastodon and Telegram are live. Instagram, Threads, Facebook, TikTok, YouTube, Pinterest and Reddit are coming and need platform review or are not built yet. Video isn't supported on any network yet. GET /v1/platforms reports live status from the server's configuration.
Is there a free social media API?
Bluesky's API is free to use for posting. LinkedIn doesn't charge per call for member posts. X charges per request with no free posting tier on its pricing page. Our Free plan covers 3 active accounts and 100 posts a month with every feature, so you can build and test without paying.
Do I need my own developer app on each network?
Not with a unified API. Account owners connect through our apps with a connect link, and you hold one API key. If you go first-party instead, you register an app on each network and pass each network's review before posting for anyone outside your own team.
Is there a dashboard?
No, on purpose. Everything runs through the REST API, the MCP server and webhooks. If you want a calendar and a drag-and-drop composer for a social media team, a scheduler like Postiz or Buffer is the better fit, and our comparison pages say so.
What happens if a post fails on one network?
The other accounts still publish. The post comes back partially_published, the failed account carries an error with a code, a message and a fix, and transient errors retry on their own at 30 seconds, 2, 10 and 30 minutes and 2 hours before the target is marked failed.
Get an API key and send your first post in five minutes.