Publishing

Social Accounts

Connect social accounts, find their IDs, and handle accounts that need reconnecting.

A social account is one connected profile, page or channel. Every post targets accounts by their Relaycast id.

Supported platforms

Platformplatform valueHow to connect
X (Twitter)twitterDashboard (OAuth)
InstagraminstagramDashboard (OAuth)
FacebookfacebookDashboard (OAuth)
LinkedInlinkedinDashboard (OAuth)
TikToktiktokDashboard (OAuth)
YouTubeyoutubeDashboard (OAuth)
ThreadsthreadsDashboard (OAuth)
PinterestpinterestDashboard (OAuth)
Google Business Profilegoogle_businessDashboard (OAuth)
BlueskyblueskyDashboard or API (app password)

Each platform has its own requirements and limits. See the platform guides.

Connect in the dashboard

  1. Open Integrations at https://social-publish-kappa.vercel.app/dashboard/integrations.
  2. Click New integration and choose a platform.
  3. Optionally pick a social group and, if you've added one, your own OAuth app.
  4. Approve access on the platform's consent screen. You return to the dashboard with the account connected.

Only project owners and admins can connect or disconnect accounts.

OAuth needs the account owner to approve access in a browser, so the API can't connect an OAuth account on its own. Instead, create a connect link with POST /v1/accounts/connect-links and send your user to it. They approve access on the platform's consent screen, without a Relaycast account, and come back to your redirectUrl with the new account's id:

curl -X POST https://social-publish-api.onrender.com/v1/accounts/connect-links   -H "x-access-key: $RELAYCAST_API_KEY"   -H "content-type: application/json"   -d '{ "platform": "youtube", "redirectUrl": "https://app.example.com/integrations/done" }'

Each link works once and expires (60 minutes by default).

Connect Bluesky with the API

Bluesky uses app passwords instead of OAuth, so you can connect it with a request. Create an app password in Bluesky's settings, then send your handle and the app password:

curl -X POST https://social-publish-api.onrender.com/v1/accounts/bluesky \
  -H "x-access-key: $RELAYCAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "identifier": "yourname.bsky.social", "appPassword": "xxxx-xxxx-xxxx-xxxx" }'
const res = await fetch("https://social-publish-api.onrender.com/v1/accounts/bluesky", {
  method: "POST",
  headers: { "x-access-key": process.env.RELAYCAST_API_KEY!, "Content-Type": "application/json" },
  body: JSON.stringify({ identifier: "yourname.bsky.social", appPassword: process.env.BLUESKY_APP_PASSWORD }),
});
const { data: account } = await res.json();
res = requests.post(
    "https://social-publish-api.onrender.com/v1/accounts/bluesky",
    headers={"x-access-key": os.environ["RELAYCAST_API_KEY"]},
    json={"identifier": "yourname.bsky.social", "appPassword": os.environ["BLUESKY_APP_PASSWORD"]},
)
account = res.json()["data"]

A successful call returns 201 with the account. If Bluesky rejects the credentials you get 400 invalid_credentials. Connecting an account that's already connected updates its credentials and keeps the same id. See Connect Bluesky.

List accounts

GET /v1/accounts returns every account in the project that isn't disconnected:

curl https://social-publish-api.onrender.com/v1/accounts -H "x-access-key: $RELAYCAST_API_KEY"
{
  "data": [
    {
      "id": "8f1c2a4e-5b6d-4e7f-9a0b-1c2d3e4f5a6b",
      "platform": "instagram",
      "handle": "acme.studio",
      "displayName": "Acme Studio",
      "avatarUrl": "https://...",
      "status": "active",
      "groupId": "c3d4e5f6-0000-4000-8000-000000000001",
      "oauthAppId": null,
      "createdAt": "2026-09-30T10:12:00.000Z"
    }
  ]
}
FieldDescription
idUse this as targets[].accountId.
platformOne of the values in the table above.
handle, displayName, avatarUrlProfile details from the platform at connect time.
statusactive or reconnect_required.
groupIdThe social group, or null for Default.
oauthAppIdYour own OAuth app used to connect it, or null for the Relaycast app.

There's no pagination: all accounts are returned in one response. See List accounts.

Reconnecting accounts

If a platform revokes access (the user changed their password, removed the app, or a token can't be refreshed), the failing target gets errorCode: "auth_revoked" and the account's status changes to reconnect_required. The dashboard marks it Reconnect needed.

Posts that target an inactive account are rejected up front:

{
  "error": {
    "code": "account_inactive",
    "message": "Some accounts need reconnecting",
    "details": { "accountIds": ["8f1c2a4e-5b6d-4e7f-9a0b-1c2d3e4f5a6b"] }
  }
}

Reconnect by connecting the same profile again from Integrations. Reconnecting the same platform account keeps its id, so you don't need to update stored IDs.

Disconnecting

Disconnecting an account in the dashboard removes its stored credentials and hides it from GET /v1/accounts. Past posts that used it stay in your history. There's no API endpoint to disconnect an account.

This page is also available as Markdown.