Accounts

Connect Bluesky

Connect or reconnect a Bluesky account with its handle and an app password.

POST https://social-publish-api.onrender.com/v1/accounts/bluesky

Signs in to Bluesky with the handle and app password, and saves the account to your project. Bluesky is the only platform you can connect with a single API call; OAuth platforms connect from Integrations in the dashboard, or through a connect link your user opens.

Create an app password in the Bluesky app under Settings → Privacy and security → App passwords. Don't use your main Bluesky password.

Calling this again for the same Bluesky account (same DID) updates its credentials in place and sets it back to active; the account id stays the same. Use this to fix an account in reconnect_required.

Headers

HeaderRequiredDescription
x-access-keyYes*Your API key. *Or send Authorization: Bearer <key>.
content-typeYesapplication/json

Body

FieldTypeRequiredDescription
identifierstringYesBluesky handle (for example acme.bsky.social) or account email. At least 3 characters.
appPasswordstringYesBluesky app password. At least 8 characters.

Request

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": "acme.bsky.social", "appPassword": "abcd-efgh-ijkl-mnop" }'
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: "acme.bsky.social",
    appPassword: process.env.BLUESKY_APP_PASSWORD!,
  }),
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data: account } = await res.json();
import os, requests

res = requests.post(
    "https://social-publish-api.onrender.com/v1/accounts/bluesky",
    headers={"x-access-key": os.environ["RELAYCAST_API_KEY"]},
    json={"identifier": "acme.bsky.social", "appPassword": os.environ["BLUESKY_APP_PASSWORD"]},
)
res.raise_for_status()
account = res.json()["data"]

Response

Returns the connected account, with the same fields as List accounts.

Response 201
{
  "data": {
    "id": "7c6b5a49-3827-4e1d-8c0b-9a8f7e6d5c4b",
    "platform": "bluesky",
    "handle": "acme.bsky.social",
    "displayName": null,
    "avatarUrl": null,
    "status": "active",
    "groupId": null,
    "oauthAppId": null,
    "createdAt": "2026-10-05T09:14:03.218Z"
  }
}

The status is 201 for reconnects too.

Errors

StatusCodeWhen
400invalid_jsonThe body isn't valid JSON.
400validation_erroridentifier or appPassword is missing or too short. details lists the issues.
400invalid_credentialsBluesky rejected the handle or app password.
401unauthorizedMissing or invalid API key.
429rate_limitedRate limit exceeded for this key.
Response 400
{
  "error": {
    "code": "invalid_credentials",
    "message": "Bluesky rejected these credentials"
  }
}

Accounts are signed in through bsky.social. See the Bluesky guide for what you can post.

This page is also available as Markdown.