Build on Bluesky
Make your first post to the Bluesky app via the API in under 5 minutes — then keep going with the guides below.
Creating a post
Write your first record with rich text.
Viewing feeds
Fetch and render timelines and custom feeds.
Likes & reposts
Create interactions between records.
Profiles
Resolve handles, DIDs, and profile data.
Install a library
The examples below use TypeScript, Python, Go, and curl. These are a few of the libraries available for atproto; for other languages and the full list of community-maintained SDKs, see atproto.com/sdks.
- TypeScript
- Python
- Go
- CURL
Install @bsky/sdk and the atproto client packages using your preferred package manager.
npm install @bsky/sdk @atproto/lex @atproto/lex-password-session
Install atproto using your preferred package manager.
pip install atproto
Add the Go SDK to your module.
go get github.com/bluesky-social/indigo
Install curl if you need to. It comes pre-installed on most operating systems.
Create a session
Log in with your handle and an app password to create an authentication session. (Use an app password rather than your main account password.)
- TypeScript
- Python
- Go
- CURL
import { Client } from '@atproto/lex'
import { PasswordSession } from '@atproto/lex-password-session'
const session = await PasswordSession.login({
service: 'https://bsky.social',
identifier: 'handle.example.com',
password: 'hunter2'
})
const client = new Client(session)
from atproto import Client
client = Client()
client.login('handle.example.com', 'hunter2')
// These imports cover this whole Get Started page.
import (
"context"
"time"
comatproto "github.com/bluesky-social/indigo/api/atproto"
appbsky "github.com/bluesky-social/indigo/api/bsky"
"github.com/bluesky-social/indigo/atproto/atclient"
"github.com/bluesky-social/indigo/atproto/identity"
lexutil "github.com/bluesky-social/indigo/lex/util"
)
ctx := context.Background()
client, _ := atclient.LoginWithPassword(ctx,
identity.DefaultDirectory(), // resolves the handle's PDS for you
"handle.example.com", // identifier
"hunter2", // app password
"", // optional 2FA token
nil, // optional refresh callback
)
Replace $BLUESKY_HANDLE and $BLUESKY_PASSWORD with your credentials, and $PDSHOST with your PDS host (including https://).
curl -X POST $PDSHOST/xrpc/com.atproto.server.createSession \
-H "Content-Type: application/json" \
-d '{"identifier": "'"$BLUESKY_HANDLE"'", "password": "'"$BLUESKY_PASSWORD"'"}'
The com.atproto.server.createSession API endpoint returns a session object containing two API tokens:
accessJwt: an access token which is used to authenticate requests but expires after a few minutesrefreshJwt: a refresh token which lasts longer and is used only to update the session with a new access token
The session object stores this information for you (and refreshes the access token automatically), and the client will include it in the headers of its requests.
The client instance stores and manages this session information for you, and will include it in the headers of its requests.
The returned client stores this session information for you, and will include it in the headers of its requests.
Create a post
Now you can create a post by sending a POST request to the createRecord endpoint.
- TypeScript
- Python
- Go
- CURL
import { post } from '@bsky/sdk'
await client.call(post, {
text: 'Hello world! I posted this via the API.'
})
post = client.send_post('Hello world! I posted this via the API.')
post := &appbsky.FeedPost{
Text: "Hello world! I posted this via the API.",
CreatedAt: time.Now().UTC().Format(time.RFC3339),
}
resp, _ := comatproto.RepoCreateRecord(ctx, client, &comatproto.RepoCreateRecord_Input{
Repo: client.AccountDID.String(),
Collection: "app.bsky.feed.post",
Record: &lexutil.LexiconTypeDecoder{Val: post},
})
Replace $BLUESKY_HANDLE with your handle, $PDSHOST with your PDS host (including https://), and $ACCESS_JWT with the JWT in the response from createSession.
curl -X POST $PDSHOST/xrpc/com.atproto.repo.createRecord \
-H "Authorization: Bearer $ACCESS_JWT" \
-H "Content-Type: application/json" \
-d "{\"repo\": \"$BLUESKY_HANDLE\", \"collection\": \"app.bsky.feed.post\", \"record\": {\"text\": \"Hello world! I posted this via the API.\", \"createdAt\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}}"
This will return an object containing the post's URI and a CID (a hash of the content).
{
"uri": "at://did:plc:abc123..../app.bsky.feed.post/xyz...",
"cid": "abc..."
}
post.uri # at://did:plc:abc123..../app.bsky.feed.post/xyz...
post.cid # abc...
resp.Uri // at://did:plc:abc123..../app.bsky.feed.post/xyz...
resp.Cid // abc...
{
"uri": "at://did:plc:abc123..../app.bsky.feed.post/xyz...",
"cid": "abc..."
}
Check out your profile to see the post you just created!
Next Steps
- Keep going with the Bluesky API guides, like creating a post with rich text or viewing feeds.
- Building an app with end-user login? Use OAuth for authentication instead of password auth (bots and command-line tools can stick with passwords).
- Sync the network in realtime with Jetstream or a Relay.
- Find more tutorials and guides on atproto.com.