TL;DR:

Apps sign into the user's PDS to access their account
Apps can directly read and write repo records
Most interactions occur through higher-level lexicons

Applications model#

Applications on the AT Protocol connect to the user's Personal Data Server (PDS) to access their account. Once a session is established, the app can use the lexicons implemented by the PDS to drive behaviors.

In this guide, we'll step through a couple of common patterns (with simple code examples) to help you develop an intuition about this. All APIs shown below are generated using Lexicon's code-generator CLI.

Signing in#

Sign-in and authentication is a simple session-oriented process. The com.atproto.session lexicon includes APIs for creating and managing these sessions.

// create an API instance with my PDS
const api = AtpApi.service('my-pds.com')

// sign in using my username and password
const res = await api.com.atproto.session.create({}, {
  username: 'alice.host.com',
  password: 'hunter2'
})

// configure future calls to include the token in the Authorization header
api.setHeader('Authorization', `Bearer ${res.data.accessJwt}`)

Repo CRUD#

Every user has a public data repository. The application can do basic CRUD on records using the API.

await api.com.atproto.repo.listRecords({
  repo: 'alice.com',
  type: 'app.bsky.post'
})
await api.com.atproto.repo.getRecord({
  repo: 'alice.com',
  type: 'app.bsky.post',
  tid: '1'
})
await api.com.atproto.repo.createRecord({
  repo: 'alice.com',
  type: 'app.bsky.post'
}, {
  text: 'Second post!',
  createdAt: (new Date()).toISOString()
})
await api.com.atproto.repo.putRecord({
  repo: 'alice.com',
  type: 'app.bsky.post',
  tid: '1'
}, {
  text: 'Hello universe!',
  createdAt: originalPost.data.createdAt
})
await api.com.atproto.repo.deleteRecord({
  repo: 'alice.com',
  type: 'app.bsky.post',
  tid: '1'
})

You may notice that the repo above is identified by a domain name alice.com. Take a look at the Identity guide to learn more about that.

Record types#

If you're noticing the "type" field and wondering how that works, see the Intro to Lexicon guide. Here is a short list of types that are currently used by the ATP software.

You'll notice "cids" in some of the schemas. A "cid" is a "Content ID," a sha256 hash of some referenced content. These are used to ensure integrity; for instance, a like includes the cid of the post being liked so that a future edit can be detected and noted in the UI.

app.bsky.graph.follow#

A social follow. Example:

{
  $type: 'app.bsky.graph.follow',
  subject: {
    did: 'did:plc:bv6ggog3tya2z3vxsub7hnal',
    declarationCid: 'bafyreid27zk7lbis4zw5fz4podbvbs4fc5ivwji3dmrwa6zggnj4bnd57u'
  },
  createdAt: '2022-10-10T00:39:08.609Z'
}

app.bsky.feed.like#

A like on a piece of content. Example:

{
  $type: 'app.bsky.feed.like',
  subject: {
    uri: 'at://did:plc:bv6ggog3tya2z3vxsub7hnal/app.bsky.post/1',
    cid: 'bafyreif5lqnk3tgbhi5vgqd6wy5dtovfgndhwta6bwla4iqaohuf2yd764
  }
  createdAt: '2022-10-10T00:39:08.609Z'
}

app.bsky.feed.post#

A microblog post. Example:

{
  $type: 'app.bsky.feed.post',
  text: 'Hello, world!',
  createdAt: '2022-10-10T00:39:08.609Z'
}

app.bsky.actor.profile#

A user profile. Example:

{
  $type: 'app.bsky.actor.profile',
  displayName: 'Alice',
  description: 'A cool hacker'
}

app.bsky.feed.repost#

A repost of an existing microblog post (similar to retweets). Example:

{
  $type: 'app.bsky.feed.repost',
  subject: {
    uri: 'at://did:plc:bv6ggog3tya2z3vxsub7hnal/app.bsky.post/1',
    cid: 'bafyreif5lqnk3tgbhi5vgqd6wy5dtovfgndhwta6bwla4iqaohuf2yd764
  }
  createdAt: '2022-10-10T00:39:08.609Z'
}

Social APIs#

While there's a lot that can be done by repo CRUD and other low-level com.atproto.* APIs, the app.bsky.* lexicon provides more powerful and easy-to-use APIs for social applications.

await api.app.bsky.feed.getTimeline()
await api.app.bsky.feed.getAuthorFeed({author: 'alice.com'})
await api.app.bsky.feed.getPostThread({uri: 'at://alice.com/app.bsky.post/1'})
await api.app.bsky.feed.getLikedBy({uri: 'at://alice.com/app.bsky.post/1'})
await api.app.bsky.feed.getRepostedBy({uri: 'at://alice.com/app.bsky.post/1'})
await api.app.bsky.actor.getProfile({user: 'alice.com'})
await api.app.bsky.graph.getFollowers({user: 'alice.com'})
await api.app.bsky.graph.getFollows({user: 'alice.com'})
await api.app.bsky.notification.list()
await api.app.bsky.notification.getCount()
await api.app.bsky.notification.updateSeen()

See what's next.Join the private beta.

The AT Protocol will launch soon.
Join the waitlist to try the beta before it's publicly available.

Join the waitlist