Bluesky API
Use the Crosspostify API to publish image, multi-image, video, and text posts to Bluesky — the open, decentralized social network built on the AT Protocol.
Bluesky is a decentralized social network built on the AT Protocol — an open standard for social networking that gives users control over their identity and data. It has grown rapidly as an alternative to X/Twitter, with a strong community of developers, journalists, researchers, and creators.
The Crosspostify Bluesky integration supports all four post types: image, multi-image, video, and text. Bluesky posts are called skeets and have a 300-character limit. The title parameter is not used on Bluesky — all content goes in caption.
This page covers everything specific to Bluesky when using the Crosspostify API. For general authentication, rate limits, and error handling, see the full API Reference.
Bluesky-Specific Parameters
Bluesky has a minimal parameter set. There are no platform-exclusive fields — just accountId and caption. The title parameter is not rendered on Bluesky and should be omitted.
accountId✓ AppliesRequired. Your Bluesky account ID from /social-accounts.caption✓ AppliesThe post text (skeet). Max 300 characters. Hashtags and @mentions are parsed as rich text facets.title✗ IgnoredNot rendered on Bluesky — omit this field. All content goes in caption.boardId✗ IgnoredPinterest only — ignored for Bluesky.is_aigc✗ IgnoredTikTok only — ignored for Bluesky.facebookFirstComment✗ IgnoredFacebook only — ignored for Bluesky.textFormatPresetId✗ IgnoredFacebook only — ignored for Bluesky.privacy✗ IgnoredYouTube only — all Bluesky posts are public.categoryId✗ IgnoredYouTube only — ignored for Bluesky.tags✗ IgnoredYouTube only — use #hashtags inline in caption instead.Bluesky enforces a strict 300-character limit per post. Crosspostify will return a validation error if your caption exceeds this limit. Plan your content accordingly — Bluesky rewards concise, punchy writing.
Bluesky uses a rich text system called facets to parse inline links, hashtags, and @mentions. Crosspostify automatically detects #hashtags and @handles in your caption and converts them to clickable AT Protocol facets — no extra configuration needed.
Supported Endpoints
Bluesky supports all four Crosspostify post types:
/post/imageImage PostPublish a single image to Bluesky. The image is embedded inline in the post alongside the caption text.
Image Post Notes
- Caption and image appear together in a single post — caption counts toward the 300-character limit
- Images are displayed inline in the feed with no cropping
- Square (1:1) and landscape (16:9) images work best in the Bluesky feed
- Upload your image first via
POST /mediaand use the returnedmediaId - All datetime values must be in UTC timezone (ISO 8601 format with
Zsuffix) - Omit
scheduledDateto post immediately
Request Body
mediaIdstringrequiredThe ID of the uploaded image file. Obtain this from POST /media.
scheduledDatestringoptionalSchedule the post for a future time (ISO 8601 with 'Z' suffix). Omit to post immediately.
postsarrayrequiredArray of post objects. Include one object per Bluesky account.
posts[].accountIdstringrequiredThe Bluesky account ID. Retrieve from GET /social-accounts.
posts[].captionstringoptionalPost text. Max 300 characters. Hashtags and @mentions are auto-converted to rich text facets.
Response
Code Example
curl -X POST "https://v1.api.crosspostify.com/post/image" \
-H "X-API-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"mediaId": "img_12345",
"scheduledDate": "2025-06-01T14:00:00Z",
"posts": [
{
"accountId": "acc_bluesky_321",
"caption": "Golden hour over the Dolomites. Sometimes you just have to put the camera down and breathe it in. 🏔️ #landscape #photography #travel"
}
]
}'/post/imagesMulti-ImagePublish up to 4 images in a single Bluesky post. Images are displayed in a grid alongside the caption text.
Bluesky supports a maximum of 4 images per post. If you provide more than 4 mediaIds, Crosspostify will return a validation error. This is a platform-level limit enforced by the AT Protocol.
Multi-Image Notes
- Maximum 4 images per post — a hard AT Protocol limit
- Images are displayed in the order provided in
mediaIds - A single shared
captionappears with all images - All images share the same 300-character caption limit
- All datetime values must be in UTC timezone (ISO 8601 format with
Zsuffix)
Request Body
mediaIdsarrayrequiredOrdered array of image media IDs. Maximum 4 images. Images appear in this order.
scheduledDatestringoptionalSchedule the post for a future time (ISO 8601 with 'Z' suffix). Omit to post immediately.
postsarrayrequiredArray of post objects. Include one object per Bluesky account.
posts[].accountIdstringrequiredThe Bluesky account ID. Retrieve from GET /social-accounts.
posts[].captionstringoptionalShared caption for all images. Max 300 characters. Hashtags and @mentions auto-converted to facets.
Response
Code Example
curl -X POST "https://v1.api.crosspostify.com/post/images" \
-H "X-API-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"mediaIds": ["img_001", "img_002", "img_003"],
"scheduledDate": "2025-06-01T14:00:00Z",
"posts": [
{
"accountId": "acc_bluesky_321",
"caption": "Three frames from this morning\'s shoot. The light was doing something special. 📷 #photography #filmlook"
}
]
}'/post/videoVideo PostPublish a native video to Bluesky. Videos are embedded inline in the post and play directly in the feed. Bluesky's video support is a newer feature with a growing audience.
Video Post Notes
- Videos are embedded natively and play inline in the Bluesky feed
- Upload your video first via
POST /mediaand use the returnedmediaId - Caption appears alongside the video — counts toward the 300-character limit
- Bluesky's tech-forward audience responds well to demos, tutorials, and build-in-public content
- All datetime values must be in UTC timezone (ISO 8601 format with
Zsuffix)
Request Body
mediaIdstringrequiredThe ID of the uploaded video file. Obtain this from POST /media.
scheduledDatestringoptionalSchedule the post for a future time (ISO 8601 with 'Z' suffix). Omit to post immediately.
postsarrayrequiredArray of post objects. Include one object per Bluesky account.
posts[].accountIdstringrequiredThe Bluesky account ID. Retrieve from GET /social-accounts.
posts[].captionstringoptionalPost text alongside the video. Max 300 characters. Hashtags and @mentions auto-converted to facets.
Response
Code Example
curl -X POST "https://v1.api.crosspostify.com/post/video" \
-H "X-API-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"mediaId": "vid_12345",
"scheduledDate": "2025-06-01T14:00:00Z",
"posts": [
{
"accountId": "acc_bluesky_321",
"caption": "Built a small tool this weekend that auto-generates alt text for images using a local model. Here\'s a quick demo. 🛠️ #buildinpublic #opensource #ai"
}
]
}'/post/textSkeetPublish a text-only post (skeet) to Bluesky. Text posts are the primary format on Bluesky — concise, conversational, and highly shareable within the community.
Text Post (Skeet) Notes
- Strict 300-character limit — plan your content carefully
- Hashtags and @mentions are auto-converted to clickable AT Protocol facets
- Line breaks are preserved in the rendered post
- Bluesky's audience skews toward developers, journalists, and open-web advocates
- Conversational, opinionated, and technical content performs well
- Threads (reply chains) are not yet supported via the Crosspostify API
Request Body
scheduledDatestringoptionalSchedule the post for a future time (ISO 8601 with 'Z' suffix). Omit to post immediately.
postsarrayrequiredArray of post objects. Include one object per Bluesky account.
posts[].accountIdstringrequiredThe Bluesky account ID. Retrieve from GET /social-accounts.
posts[].captionstringrequiredThe skeet text. Max 300 characters. Required for text posts. Hashtags and @mentions auto-converted to facets.
Response
Code Example
curl -X POST "https://v1.api.crosspostify.com/post/text" \
-H "X-API-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"scheduledDate": "2025-06-01T14:00:00Z",
"posts": [
{
"accountId": "acc_bluesky_321",
"caption": "Hot take: the best API documentation is the one that shows you a real working example in the first 10 seconds.\n\nNot a diagram. Not a concept overview. A curl command that actually runs.\n\n#devex #apidocs #buildinpublic"
}
]
}'AT Protocol
Bluesky is built on the AT Protocol (atproto) — an open, federated protocol for social networking. Unlike centralized platforms, AT Protocol gives users portable identities, self-hosted data, and the ability to migrate between providers. Here's what that means for API users:
Decentralized Identity
- Bluesky handles are domain-based (e.g. @you.bsky.social)
- Custom domains work as handles (e.g. @yourname.com)
- DIDs (Decentralized Identifiers) are the underlying identity layer
- Crosspostify abstracts this — just use your accountId
Personal Data Servers (PDS)
- All posts are stored in a user-controlled Personal Data Server
- Posts are publicly accessible via the AT Protocol firehose
- Content is portable — users can migrate their data
- Crosspostify handles PDS interaction transparently
Rich Text Facets
- Bluesky uses "facets" for inline rich text (links, hashtags, mentions)
- Crosspostify auto-detects #hashtags and @mentions in captions
- Facets are converted to clickable elements in the Bluesky UI
- URLs in captions are also auto-linked as facets
Open & Transparent
- All posts are public by default — no private posts via API
- Post records are cryptographically signed
- The AT Protocol spec is open source and community-governed
- No algorithmic feed manipulation — chronological by default
Crosspostify handles all AT Protocol complexity — DID resolution, PDS authentication, lexicon record creation, and facet parsing — behind the scenes. You just send a standard Crosspostify API request and we take care of the rest.
Content Guidelines
Bluesky's audience is tech-forward, values-driven, and highly engaged. Content that is authentic, conversational, and community-native performs best. The platform skews toward developers, journalists, researchers, and open-web advocates.
Image Requirements
- Format: JPG, PNG, or GIF
- Max file size: 20MB per image
- Images appear inline in the feed
- Max 4 images per post
Video Requirements
- Format: MP4 recommended
- Max file size: 100MB via Crosspostify
- Max duration: approx. 3 minutes
- Videos autoplay in the feed
Text & Caption Tips
- Strict 300-character limit
- Emojis count as 1 character (usually)
- URLs are auto-linked but count toward the limit
- Short, conversational posts work best
Scheduling
- Minimum lead time: ~10 minutes ahead
- All times must be UTC (ISO 8601 + Z)
- Omit scheduledDate to post immediately
- Consistent posting builds algorithmic feed ranking