Bluesky

How to Post to Bluesky via API

The request flow for publishing to Bluesky programmatically.

Quick answer

To post to Bluesky via API, connect the account with its handle and an app password (generated at bsky.app under Settings → App passwords) through PostGate’s hosted connection page, then send POST /api/posts with post.body, the profile ID, and optional media. Text is limited to 300 graphemes, with up to 4 images and no video yet.

Bluesky is the one platform in PostGate's catalog where the underlying protocol — the AT Protocol — is genuinely different from the REST APIs behind Instagram, LinkedIn, or TikTok. That shows up in exactly one place for you as an integrator: how the account gets connected. Everything after that — creating the post, tracking delivery, reading the result — uses the same request shape as every other platform.

This walkthrough covers the full flow end to end: register an origin, connect an account with an app password, publish, and confirm delivery.

01

What do you need before you start?

A PostGate API key, a registered connect origin for the hosted redirect, and a Bluesky account with an app password generated at bsky.app under Settings → App passwords.

The account's main login password should never be entered anywhere outside bsky.app itself — that's exactly what app passwords exist to avoid.

02

Step 1: register your product’s origin

PostGate only redirects a finished connection back to an origin you've registered. Do this once per product.
Allow an originPostGate API
curl -X POST https://postgate.studio/api/connect-origins \
  -H "Authorization: Bearer $POSTGATE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "origin": "https://app.example.com", "label": "Production SaaS" }'
03

Step 2: create a hosted connection for Bluesky

Request a connection URL with platform: "bluesky" and redirect the customer's browser to it. The URL expires after 15 minutes.

Create connection URLPostGate API
curl -X POST https://postgate.studio/api/profiles/connect \
  -H "Authorization: Bearer $POSTGATE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "bluesky",
    "profile_group_id": "grp_acme123",
    "return_url": "https://app.example.com/settings/social"
  }'
04

Step 3: the customer enters handle and app password

On the hosted page, the customer enters their Bluesky handle and app password directly — this is the one credential-based exception among PostGate's mostly-OAuth connection flows. PostGate exchanges it for a session server side and never exposes it back to your product. When it finishes, your browser lands back on return_url with connected=1&connection_platform=bluesky, or connection_error if the customer canceled or the credential was rejected.
05

Step 4: publish a post

Publishing uses the same envelope as any other platform — post.body, a profiles array, and optional media. A stable Idempotency-Key makes the request safe to retry.
Publish nowPostGate API
curl -X POST "https://postgate.studio/api/posts?profile_group_id=grp_acme123" \
  -H "Authorization: Bearer $POSTGATE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: bsky-launch-001" \
  -d '{
    "post": { "body": "Launch day. 🚀" },
    "profiles": ["pro_bluesky123"],
    "media": ["https://cdn.example.com/launch.jpg"]
  }'
06

Step 5: confirm delivery

Read the post back to see per-target status. A Bluesky target that reached published carries a permalink you can show the customer or store for your own records.
Read post statusPostGate API
curl https://postgate.studio/api/posts/post_01JXYZ \
  -H "Authorization: Bearer $POSTGATE_API_KEY"
07

What gotchas are specific to Bluesky?

300-grapheme text limit, up to 4 images and no video yet, and a health check (GET /api/profiles/{id}/health) is worth calling before a big send — an app password can be revoked from Bluesky's side at any time, which shows up as reconnect_required rather than a silent failure.

Frequently asked questions

Do I need an app password to post to Bluesky via API?

Yes. On PostGate’s hosted page the customer enters their Bluesky handle and an app password generated at bsky.app under Settings → App passwords — the one credential-based exception among PostGate’s mostly-OAuth connection flows. The account’s main login password should never be entered anywhere outside bsky.app itself; that’s exactly what app passwords exist to avoid.

Is posting to Bluesky different because of the AT Protocol?

Only at connection time. The AT Protocol is genuinely different from the REST APIs behind Instagram, LinkedIn, or TikTok, but that shows up in exactly one place for an integrator: how the account gets connected. Everything after that — creating the post, tracking delivery, reading the result — uses the same request shape as every other platform.

What are Bluesky’s limits for posts created via API?

A 300-grapheme text limit, up to 4 images per post, and no video yet. The publish envelope itself is standard: post.body, a profiles array, optional media, and a stable Idempotency-Key to make the request safe to retry.

What happens if the Bluesky app password is revoked?

An app password can be revoked from Bluesky’s side at any time. That shows up as reconnect_required rather than a silent failure — which is why calling the profile health check (GET /api/profiles/{id}/health) is worth doing before a big send.

Build it with PostGate

One API for every social platform your customers care about — sandboxed, documented, and ready today.

Start building Read the docs