Bluesky

Bluesky API: How to Post to Bluesky via API

The official AT Protocol API is open and free. Here is what posting with it involves, and when a single Publora integration for Bluesky plus nine other networks makes more sense.

Bluesky runs on the AT Protocol, and its API is open. There is no app review, no developer application and no fee. You log in with an app password or OAuth, write an app.bsky.feed.post record, and the post is live. For a bot or a script that only posts to Bluesky, the official API is the simplest way to do it, and we would recommend it.

The work shows up in the details: links and hashtags are not clickable unless you add rich-text facets with byte offsets, images are uploaded as blobs first, and sessions need refreshing. None of it is hard, but it is Bluesky-specific code you then maintain next to every other network you post to.

Publora's value for Bluesky is not access. It is one integration for ten networks, scheduling without running your own queue, engagement stats, and an MCP server so AI agents like Claude can post for you.

Posting through the official Bluesky API compared with one Publora API request

The official Bluesky API

A Bluesky post is a repository record of type app.bsky.feed.post, created with com.atproto.repo.createRecord on the account's PDS. The record needs text and a createdAt timestamp. Mentions, links and hashtags are rich-text facets that point at byte ranges in the UTF-8 text. Images are uploaded as blobs and referenced from an embed.

What posting requires

  1. For your own account: create an app password in Bluesky settings and start a session with com.atproto.server.createSession.
  2. For other people's accounts: implement atproto OAuth, which uses PKCE, PAR and DPoP, with client metadata published at a URL that serves as your client_id.
  3. No developer registration, app review or API key is required.
  4. Post with createRecord, calculate facet byte offsets for links and mentions, and upload images as blobs before referencing them.

Cost: Free. Bluesky does not charge for API access; the limits below are the only constraints.

Official limits

Post text300 graphemes (3,000 bytes)
Images per post4, up to 2,000,000 bytes each
Record writes per account5,000 points per hour, 35,000 per day (create = 3 points)
Posts implied by write budgetUp to about 1,666 creates per hour
createSession30 per 5 minutes, 300 per day per account
API requests via PDS3,000 per 5 minutes per IP
Blob upload size (PDS)50 MB

Common gotchas

  • Facets use UTF-8 byte offsets, not character positions. Emoji and non-Latin text shift the offsets and break links if you count characters.
  • Links and hashtags in plain text are not clickable until you add the facets yourself.
  • createSession is limited to 300 per day per account, so a script that logs in on every run should reuse and refresh its session.
  • The 300 limit counts graphemes, so a JavaScript string length check is not the same thing.
  • Other atproto hosts can set different rate limits than Bluesky's own PDS.

Posting to Bluesky through Publora

One integration, ten networks

The same POST /create-post body that posts to Bluesky also posts to LinkedIn, X, Threads, Mastodon and the rest. Add connection IDs to the platforms array.

Facets calculated for you

Hashtags and URLs in your text become clickable facets with correct byte offsets, including for emoji and non-Latin scripts.

Scheduling without a queue

Send scheduledTime in UTC and Publora publishes at that time. No cron job, worker or retry logic on your side.

Stats for agents and scripts

On Pro, read likes, replies, reposts, quotes and saves for posts Publora published, plus follower counts, through the API or the post_stats and profile_stats MCP tools.

Connect with an app password

You enter your handle and a Bluesky app password once in the Publora dashboard. Revoke that app password in Bluesky any time to cut access.

Official Bluesky APIPublora API
AccessOpen; no review or registrationPublora account and API key
PriceFreeFree Starter plan; Pro $5.99 per account per month
AuthApp password session or atproto OAuthx-publora-key header; app password stored once
Links and hashtagsBuild facets with byte offsetsDetected automatically
SchedulingRun your own schedulerscheduledTime in UTC
Threads (reply chains)Possible by writing reply recordsNot supported; posts over 300 characters are rejected
Image alt textSupported in the image embedNot settable through the REST API yet
Other networksBluesky and atproto apps only10 networks in one request

Post to Bluesky via API

curl -X POST https://api.publora.com/api/v1/create-post \
  -H "Content-Type: application/json" \
  -H "x-publora-key: sk_YOUR_API_KEY" \
  -d '{
    "content": "Our analytics view now shows reposts and quotes side by side. Details: https://example.com/changelog #buildinpublic",
    "platforms": ["bluesky-did:plc:abc123xyz"],
    "scheduledTime": "2026-10-07T16:00:00.000Z",
    "mediaUrls": ["https://example.com/images/analytics-view.png"]
  }'
# { "success": true, "postGroupId": "...", "scheduledTime": "2026-10-07T16:00:00.000Z" }
import requests

response = requests.post(
    "https://api.publora.com/api/v1/create-post",
    headers={
        "Content-Type": "application/json",
        "x-publora-key": "sk_YOUR_API_KEY",
    },
    json={
        # Must fit in 300 characters; longer text is rejected, not split.
        "content": "Our analytics view now shows reposts and quotes side by side. #buildinpublic",
        "platforms": ["bluesky-did:plc:abc123xyz", "mastodon-109876543210"],
        "scheduledTime": "2026-10-07T16:00:00.000Z",
    },
)
print(response.json())  # {'success': True, 'postGroupId': '...', 'scheduledTime': '...'}

Or let an AI agent post

Connect any MCP client to mcp.publora.com:

  • “Shorten this announcement to under 280 characters and schedule it to my Bluesky and Mastodon accounts for Thursday at 16:00 UTC.”
  • “Pull post stats for my Bluesky posts from last week and tell me which ones got the most reposts.”
  • “Schedule a Bluesky post with this screenshot URL tomorrow at 10:00 UTC, with the link and #opensource in the text.”

Where you get the key and connect agents

Publora dashboard API page with API keys and code examples
API page: create a key and copy ready-made examples.
Publora dashboard MCP page listing Claude, Claude Code, Codex, Cursor, VS Code and Windsurf
MCP page: pick your AI app for a one-step setup.

Bluesky API FAQ

Is the Bluesky API free?

Yes. The AT Protocol API has no fee and no app review. You need an account, an app password or OAuth, and to stay within the rate limits.

Should I use the official Bluesky API or Publora?

If you post only to Bluesky, the official API is straightforward and free. Publora is useful when Bluesky is one of several networks, when you want scheduling without running a queue, or when an AI agent should post through MCP.

What are the Bluesky API rate limits?

Bluesky's PDS allows 5,000 write points per hour and 35,000 per day per account, with a create costing 3 points, plus 3,000 API requests per 5 minutes per IP. createSession is limited to 30 per 5 minutes and 300 per day.

Can Publora post a Bluesky thread or add image alt text?

Not currently. Bluesky posts through Publora must fit in 300 characters, and alt text cannot be set through the REST API.

Do I need OAuth to connect Bluesky to Publora?

No. You connect with your handle and an app password in the Publora dashboard, then use your Publora API key. The free Starter plan includes the API and MCP: 3 accounts, 15 posts per month, up to 3 scheduled posts at a time, 7 days ahead.