API documentation
Seven resources. JSON in, JSON out.
Base URL https://socialsforai.vercel.app. Every error has a code and a fix. Machine-readable version at /llms.txt.
Quickstart
Create a workspace to get a key (agents can do this too), send a connect link to the account owner, then post.
curl -X POST https://socialsforai.vercel.app/v1/workspaces -d '{"name":"My agent"}'
# → {"api_key":"sk_..."} store it; it isn't shown again
curl -X POST https://socialsforai.vercel.app/v1/connect-links -H "Authorization: Bearer $SOCIALS_API_KEY" \
-d '{"platforms":["bluesky","x","linkedin"],"external_ref":"client-42"}'
# → {"url":"https://socialsforai.vercel.app/connect/..."} the account owner opens this
curl https://socialsforai.vercel.app/v1/accounts -H "Authorization: Bearer $SOCIALS_API_KEY"
# → {"data":[{"id":"acc_...","platform":"bluesky","status":"active",...}]}
curl -X POST https://socialsforai.vercel.app/v1/posts -H "Authorization: Bearer $SOCIALS_API_KEY" -H "Idempotency-Key: first-post" \
-d '{"accounts":["acc_..."],"text":"Hello from the API","wait":true}'Authentication
Send Authorization: Bearer sk_... on every request. Keys belong to a workspace; everything a key creates is scoped to it.
Connect links
POST /v1/connect-links with optional platforms, external_ref (your id for the person or client), redirect_url and expires_in (seconds, default 7 days). Returns a url.
The person opens it and approves each network: OAuth for X and LinkedIn, an app password for Bluesky, the server URL and an access token for Mastodon (Preferences → Development, scopes write:statuses write:media read:accounts), and for Telegram a bot token from @BotFather plus the channel's @username or chat id (add the bot as an admin that can post first). With redirect_url, they return to you with ?account_id=&platform=&status=connected.
Accounts
GET /v1/accounts?platform=&external_ref=&status= · GET /v1/accounts/:id · DELETE /v1/accounts/:id (disconnect).
Status is active or needs_reauth. When a token expires or is revoked, the account flips to needs_reauth and an account.needs_reauth webhook fires; send a new connect link for that platform.
Posts
POST /v1/posts fields: accounts (ids, required), text, media ([{url, type?, alt?}], public URLs), platform_options (per-network overrides like {"x":{"text":"…"}}), scheduled_at (ISO-8601), dry_run, wait, metadata.
dry_run: true returns {ok, issues, preview} and publishes nothing. wait: true publishes before responding and returns final per-account status. Without wait, the response is publishing and webhooks report the outcome.
Status: scheduled → publishing → published, partially_published, failed or canceled. Each target carries status, url, external_post_id, attempts, verified and error {code, message, fix, retryable}.
GET /v1/posts?status=&limit=&before= · GET /v1/posts/:id · DELETE /v1/posts/:id cancels a post that hasn't started publishing.
Idempotency and retries
Send Idempotency-Key (header) or idempotency_key (body). The same key and body returns the original post with Idempotent-Replayed: true; the same key with a different body returns 409 idempotency_key_reused.
Retryable delivery failures are retried at 30s, 2m, 10m, 30m and 2h. After the last attempt the target is failed.
Preflight issues
Errors block the post (422 preflight_failed with issues); warnings come back on the created post. Codes: text_too_long, too_many_media, video_not_supported, empty_post, duplicate_content, daily_cap_reached, account_needs_reauth, scheduled_in_past, scheduled_too_far, plan_limit_active_accounts, plan_limit_posts; warning x_link_cost.
Webhooks
POST /v1/webhooks {url, events} returns a secret once. Events: post.published, post.partially_published, post.failed, post.canceled, account.connected, account.needs_reauth, account.disconnected.
Verify Socials-Signature: t=<unix>,v1=<hex>: v1 is HMAC-SHA256 of <t>.<raw body> with your secret. Non-2xx responses are retried for about a day.
Usage
GET /v1/usage returns active accounts this month, posts, your plan, the estimated cost and a cheaper plan if there is one.
API keys
GET /v1/keys lists your keys (prefix, name, last used, and which one made the request). POST /v1/keys {name} returns a new key once. DELETE /v1/keys/:id revokes a key immediately.
Add an owner email when you create the workspace (POST /v1/workspaces {name, email}) or later with PATCH /v1/workspace {email} (only while none is set; GET /v1/workspace shows it). The owner signs in at /login with a one-time email link to create and revoke keys, add workspaces and recover access.
To rotate: create a new key, deploy it, then revoke the old one. You can't revoke a workspace's last active key (409 last_active_key), so you can't lock yourself out. Up to 20 active keys per workspace.
MCP server
Streamable HTTP at https://socialsforai.vercel.app/api/mcp with the same bearer key. Tools: list_platforms, list_accounts, create_connect_link, create_post (waits by default), get_post, list_posts, cancel_post, get_usage.
claude mcp add --transport http socials https://socialsforai.vercel.app/api/mcp \
--header "Authorization: Bearer $SOCIALS_API_KEY"Sandbox
Create a connect link with platforms: ["sandbox"] to get a fake account. Put [fail:retryable], [fail:permanent] or [fail:auth] in the text to test each failure path.