# OmniSocials Bluesky API

> Publish posts, images, video and threads to Bluesky, with alt text, link cards and clickable links. Read likes, reposts and followers. One API key, and the account signs in with its handle.

This is the machine-readable version of [omnisocials.com/bluesky-api](https://omnisocials.com/bluesky-api), maintained for AI agents. Facts checked against the OmniSocials app and API on October 17, 2026. Platform reference: [docs.omnisocials.com/platforms/bluesky](https://docs.omnisocials.com/platforms/bluesky). API reference: [docs.omnisocials.com/api](https://docs.omnisocials.com/api).

## Basics

- Base URL: `https://api.omnisocials.com/v1`
- Auth: `Authorization: Bearer omsk_live_...`. One key belongs to one workspace. Keys are created in the app under Settings, API.
- Channel id in `accounts`: `bluesky`. The account connects inside the OmniSocials app, not through the API.
- Rate limit: 100 requests per minute per key. A 429 carries `Retry-After`.
- Responses use a `{ "data": ... }` envelope. Create returns `201`.
- Webhooks: `post.scheduled`, `post.published`, `post.failed`, `post.approved`, `post.rejected`, signed with HMAC-SHA256 in `X-OmniSocials-Signature`.

## Skip the AT Protocol plumbing

Bluesky has no app review, but posting from your own code still means an OAuth client with DPoP-bound tokens, handle lookups, blob uploads under 2 MB, a separate video service and facets for every link. OmniSocials already built it.

- On your own: OAuth client, PDS lookup, DPoP, Token refresh, Blobs, Video jobs, Thread refs, Facets, then the first post.
- On OmniSocials: sign in, create an API key, POST. OAuth, uploads and facets done for you.

## Schedule a post

```bash
curl -X POST https://api.omnisocials.com/v1/posts/create \
  -H "Authorization: Bearer $OMNISOCIALS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "content": "New: Alt text on every image",
  "accounts": ["bluesky"],
  "media_urls": [
    {
      "url": "https://cdn.example.com/alt-text.png",
      "alt": "The ALT button on an image in the composer"
    }
  ],
  "schedule_at": "2026-10-22T18:00:00Z"
}'
```

The answer (`201`, shortened):

```json
{
  "data": {
    "id": "1024",
    "status": "scheduled",
    "app_url": "https://app.omnisocials.com/create-post/1024"
  }
}
```

## Every format, one request

Text posts, images, video and threads share one request shape. Add media URLs with their alt text, or a link for a card, and a time. OmniSocials checks the post against Bluesky’s rules before it goes out.

- **Text and link cards.** 300 characters, counted the way Bluesky counts them. A post without media gets a card for its first link. (`content`)
- **Images and video.** Up to 10 images or one video, each with alt text. Images up to 10 MB are compressed to fit Bluesky’s 2 MB limit. (`media_urls`, `alt`)
- **Threads.** 2 to 25 posts in one request, each with its own media or link card, chained as replies. (`bluesky.thread_parts`)

### Post

```json
{
  "content": "What's new: https://omnisocials.com/changelog",
  "accounts": ["bluesky"],
  "schedule_at": "2026-10-23T12:00:00Z"
}
```

### Images

```json
{
  "content": "New: Alt text on every image",
  "accounts": ["bluesky"],
  "media_urls": [
    {
      "url": "https://cdn.example.com/alt-text.png",
      "alt": "The ALT button on an image in the composer"
    }
  ],
  "schedule_at": "2026-10-22T18:00:00Z"
}
```

### Video

```json
{
  "content": "Post from your own code: SDKs in 8 languages.",
  "accounts": ["bluesky"],
  "media_urls": [
    {
      "url": "https://cdn.example.com/sdks.mp4",
      "alt": "Code that creates a post with the Node.js SDK"
    }
  ],
  "schedule_at": "2026-10-24T10:00:00Z"
}
```

### Thread

```json
{
  "content": { "default": "" },
  "accounts": ["bluesky"],
  "schedule_at": "2026-10-25T10:00:00Z",
  "bluesky": {
    "thread_parts": [
      { "text": "One request, the whole thread." },
      { "text": "The docs: https://docs.omnisocials.com/platforms/bluesky" },
      {
        "text": "Each post keeps its own media.",
        "media_urls": ["https://cdn.example.com/thread.png"]
      }
    ]
  }
}
```

## Whole threads in one request

Connect the account with its handle once. Then put 2 to 25 posts in bluesky.thread_parts: OmniSocials chains them as replies, so they read as one thread, each with its own media or link card.

`POST /v1/posts/create`:

```json
{
  "content": { "default": "" },
  "accounts": ["bluesky"],
  "schedule_at": "2026-10-25T10:00:00Z",
  "bluesky": {
    "thread_parts": [
      { "text": "One request, the whole thread." },
      { "text": "The docs: https://docs.omnisocials.com/platforms/bluesky" },
      {
        "text": "Each post keeps its own media.",
        "media_urls": ["https://cdn.example.com/thread.png"]
      }
    ]
  }
}
```

- **Sign in with your handle.** The account signs in on Bluesky over OAuth, no app password to make. Custom-domain handles and accounts on other servers work too.
- **2 to 25 posts.** Each post holds up to 10 images or one video, with alt text. If publishing stops halfway, the retry picks up where the thread stopped. (`bluesky.thread_parts`)
- **Cards, links and tags.** Links, mentions and hashtags turn clickable, and a post without media gets a card for its first link.

## Connect with a handle, post from code

Type the account’s handle in OmniSocials once and sign in on Bluesky. Create an API key, and your code posts and reports for that account.

- **Your handle, over OAuth.** No app password to create or paste. Custom-domain handles and self-hosted servers work.
- **A key per workspace.** A key only reaches its own workspace. Each workspace connects one Bluesky account.
- **What the account can post.** The accounts call lists the account with its handle and the formats it takes. (`GET /v1/accounts`, `content_types`)

`GET /v1/accounts?platform=bluesky` answers:

```json
{
  "data": [
    {
      "id": "4127_bluesky",
      "platform": "bluesky",
      "username": "omnisocials.bsky.social",
      "display_name": "OmniSocials",
      "content_types": ["post"],
      "status": "active"
    }
  ],
  "workspace_name": "OmniSocials"
}
```

## Read what Bluesky reports

Likes, replies, reposts, quotes and bookmarks per post, summed across a thread, and the account’s followers per day. The API returns the same numbers the app charts.

- **Per post and per thread.** Likes, replies, reposts, quotes and bookmarks. A thread reports the sum of its posts, and thread_parts says how many. (`/analytics/posts/:id`)
- **Per account and workspace.** A daily snapshot of the account: followers, following and posts. Plus a workspace overview. (`/analytics/accounts`, `/analytics/overview`)
- **Best times to post.** Days and hours worked out from your own Bluesky history, once 15 of your posts are analyzed. (`/analytics/best-times`)

`GET /v1/analytics/posts/1019` answers:

```json
{
  "data": {
    "post_id": "1019",
    "platforms": {
      "bluesky": {
        "metrics": {
          "likes": 48, "comments": 6,
          "reposts": 11, "quotes": 3,
          "bookmarks": 9
        },
        "thread_parts": 1
      }
    }
  }
}
```

## Bluesky’s rules, in one place

OmniSocials checks every post against them before it reaches Bluesky, so a post that is too long fails in your request, not at publish time.

| Limit | Value |
| --- | --- |
| Text | 300 characters, an emoji counts as one |
| Media | Up to 10 images or one video, not both |
| Images | Up to 10 MB, compressed under Bluesky’s 2 MB |
| Video | Up to 10 minutes and 300 MB |
| Alt text | 1,500 characters per image or video |
| Thread | 2 to 25 posts, each with its own media |
| Link card | The first link of a post without media |
| Rate limit | 100 requests a minute per API key |
| Accounts | One Bluesky account per workspace |

## Your first thread in three steps

About five minutes from sign-up to a scheduled thread on Bluesky. Then hand the key to your coding agent.

1. **Create an API key** (`Settings › API`). Start your trial, open Settings, API and create a key. It is shown once.
2. **Connect your account** (`GET /v1/accounts`). Type your handle in OmniSocials once and sign in on Bluesky. Then list it from your code.
3. **Send your first thread** (`POST /v1/posts/create`). Put the posts in bluesky.thread_parts and add schedule_at, or publish right away with create-and-publish.

## FAQ

### Do I need an app password or my own AT Protocol client?

No. The account signs in on Bluesky with its handle, through OmniSocials, over OAuth. There is no app password to create, and you never handle tokens. Your code calls the OmniSocials API with an API key.

### Which Bluesky accounts can I connect?

Any account with a handle: name.bsky.social, a custom-domain handle like yourbrand.com, or an account on a self-hosted or third-party server. Each workspace connects one Bluesky account, and the same account can be connected to several workspaces.

### Can my own users connect their Bluesky accounts through the API?

Not yet. Accounts connect inside the OmniSocials app. Every API key in that workspace can then post to the account.

### Can I schedule Bluesky posts?

Yes. Bluesky has no scheduling of its own, so OmniSocials keeps the queue and publishes at schedule_at, with a webhook when the post is live.

### How do I post a thread?

Put 2 to 25 posts in bluesky.thread_parts, each with its text and optional media_urls or media_ids. Each post takes up to 10 images or one video, and a post without media gets a link card. OmniSocials chains them with reply references, so they read as one thread.

### Do links, mentions and hashtags work?

Yes. OmniSocials turns them into clickable links (Bluesky's rich-text facets) when it publishes. A post without media gets a card for its first link, with the page's title, description and image.

### Can I add alt text to images and video?

Yes. Send a media entry as { "url": "...", "alt": "..." } in media_urls, or { "id": "...", "alt": "..." } in media, also per post in a thread. Up to 1,500 characters, published as the image or video’s alt text.

### What about Bluesky’s 2 MB image limit?

Send images up to 10 MB. OmniSocials compresses them to fit Bluesky’s 2 MB limit and sends each image’s aspect ratio, so it shows in its own shape. Video goes up to 10 minutes and 300 MB.

### Which numbers can I read?

Likes, replies, reposts, quotes and bookmarks per post, summed across a thread, and the account’s followers per day. Bluesky does not report views, reach or clicks, so the API leaves those out.

### What happens when a Bluesky post fails to publish?

When the error is temporary, OmniSocials retries it up to 3 times, 15 minutes apart. A thread picks up where it stopped, so posts that already went out are not sent again. Then post.published or post.failed fires.

### Is the Bluesky API free?

Yes. Bluesky’s AT Protocol API is open and free to call. OmniSocials adds the queue, threads, image compression and analytics on top, and the API is part of the plan, $10 per seat per month billed annually.

### What are the rate limits?

100 requests a minute per API key. Past that the API answers 429 with a Retry-After header that says when to try again.

### How much does OmniSocials cost?

One plan with every feature included: $10 per seat per month billed annually, or $12 billed monthly. Team members and client seats cost the same. Every account starts with a 14-day free trial.

The REST API, the SDKs, the CLI, webhooks and the MCP server are part of that one plan.

## Pricing

From $10 per seat a month, API included. 14-day free trial.

## Related

- [Bluesky scheduler](https://omnisocials.com/bluesky.md)
- [Bluesky MCP server](https://omnisocials.com/bluesky-mcp.md)
- [All channels](https://omnisocials.com/channels.md)
- [Bluesky character limits](https://omnisocials.com/bluesky-character-limits)
- [Bluesky video lengths](https://omnisocials.com/bluesky-video-lengths)

## Links

- Page: https://omnisocials.com/bluesky-api
- Bluesky platform docs: https://docs.omnisocials.com/platforms/bluesky
- API reference: https://docs.omnisocials.com/api
- REST API overview: https://omnisocials.com/api.md
- MCP server: https://omnisocials.com/mcp.md
- Sign up: https://app.omnisocials.com/signup
