Channels
Bluesky
How an agent publishes to Bluesky through uplika: app passwords instead of OAuth, graphemes instead of characters, and links that need a little help.
Quick reference
| Name | Type | Description |
|---|---|---|
characters | text | 300 |
images | media | up to 4 per post; more than that and the first 4 go out with a warning |
carousel | media | no carousel; images sit in the post one after another |
video | media | 1 per post |
text alone | media | allowed |
posts / 24h | limit | 11,666 |
deletes / 24h | limit | 35,000 |
status | state | live |
These numbers come from the same file the server validates against. Bluesky counts graphemes (what a reader sees as one character) and also caps UTF-8 bytes, so a post of 300 emoji can fail on the byte limit.
Why does langs matter?
Feed generators filter on the post's language. Without options.bluesky.langs the post is published but never appears in language-scoped feeds, and Bluesky has no post editing to fix it later. Set it to the language the text is actually written in, one to three BCP-47 codes.
How do links and mentions work?
Bluesky does not detect links in text. uplika builds the facets for you: URLs, @mentions and #hashtags in the text become clickable, and the first URL gets a preview card fetched from its Open Graph tags. Write the URL plainly.
How do I publish my first post?
Call publish with text and langs. Up to four images sit in a grid; one video is allowed.
curl -X POST https://api.uplika.com/v1/posts \
-H "Authorization: Bearer $UPLIKA_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Shipped nested replies today. https://uplika.com",
"accountIds": ["conn_..."],
"options": { "bluesky": { "langs": ["en"] } }
}'What options.bluesky takes
| Name | Type | Description |
|---|---|---|
langs | string[] | The language of the text, 1-3 BCP-47 codes like ["ko"] or ["en", "ko"]. Feed generators filter on this, so without it the post never appears in language-scoped feeds. Bluesky has no post editing, so this cannot be fixed after publishing. Set it to the language the text is actually written in. |
content | string | Text for this channel only. When set it replaces the shared content for this channel, and the length and media checks use it. Leave it out to use the shared content. |
Generated from the same schema the server validates with. GET /v1/platforms returns it too.
What is not available?
Editing a published post (Bluesky has none), and a carousel in the Instagram sense; several images are a grid. Deleting works and is confirmed against the account's data server, because the app view keeps returning a deleted post for a while.
Frequently asked
Do I have to give uplika my Bluesky password?
No. You create an app password in Bluesky's settings, which can be revoked on its own, and paste that into the dashboard. It goes over the request body only, never a URL.
Why is my post missing from language feeds?
Because langs was not set. Feed generators filter on it. There is no fix after publishing; delete and publish again with langs.
Why did a 300-character post get refused?
Because Bluesky also caps UTF-8 bytes at 3,000. Text heavy in emoji or ZWJ sequences can pass the grapheme count and fail the byte count; the error says which.