possum

PDS (Personal Data Server)

A PDS, or Personal Data Server, is a server that hosts a user, it will always store the user’s data repo and signing keys. It may also assign the user a handle and a DID. Many PDSes will host multiple users.

A PDS doesn’t typically run any applications itself, though it will have general account management interfaces such as the OAuth login screen. PDSes actively sync their data repos with Relays.

Lexicon

Lexicon is a schema language. It’s used in the Atmosphere to describe data records and HTTP APIs. Functionally it’s very similar to JSON-Schema and OpenAPI. Lexicon’s sole purpose is to help developers build compatible software.

Record Keys

A record key (sometimes shortened to “rkey”) is used to name and reference an individual record within the same collection of an atproto repository. It ends up as a segment in AT URIs, and in the repo MST path.

CID (Content ID)

CIDs, or Content Identifiers, are cryptographic hashes of records. They are used to track specific versions of records.

CIDs include a metadata code which indicates whether it links to a node or arbitrary binary data. In atproto, object nodes often include a string field $type that specifies their Lexicon schema.

Values

pub fn authorized(
  request: request.Request(a),
  access_token token: String,
) -> request.Request(a)

Include a access token in the request’s headers. Tokens can be acquired with create_session.

Examples

import gleam/http/request
import possum

let request =
  request.new()
  |> request.set_host("personal.data-server.pds")
  |> possum.authorized("access-token")
pub fn create_record(
  request: request.Request(a),
  did: did.Did,
  collection collection: String,
  rkey rkey: option.Option(String),
  record record: List(#(String, json.Json)),
  swap_commit swap_commit: option.Option(String),
  validate validate: option.Option(Bool),
) -> request.Request(String)

Create a single new repository record. Requires auth, implemented by PDS.

Body

  • collection: The NSID of the record collection.
  • repo: The handle or DID of the repo (aka, current account).
  • rkey: The Record Key.
  • swapCommit: Compare and swap with the previous commit by CID.
  • validate: Can be set to ‘false’ to skip Lexicon schema validation of record data, ‘true’ to require it, or leave unset to validate only for known Lexicons.

Examples

import gleam/http/request
import possum

let request =
  request.new()
  |> request.set_host("personal.data-server.pds")
  |> possum.authorized("access-token")
  |> possum.create_record(
    did,
    rkey: "wibble",
    collection: "wibble.wobble.woo",
    record: [],
    swap_commit: option.None,
    validate: option.None,
  )

Response

{
  "cid": "string",
  "uri": "string",
  "commit": {
    "cid": "string",
    "rev": "string"
  },
  "validationStatus": "valid"
}

Endpoint Docs: /xrpc/com.atproto.repo.createRecord

pub fn create_session(
  request: request.Request(a),
  did: did.Did,
  app_password app_password: String,
  allow_takendown allow_takendown: option.Option(Bool),
  auth_factor_token auth_factor_token: option.Option(String),
) -> request.Request(String)

Create an authentication session. An App Password can be generated in your Bluesky settings.

Body

  • password: App password
  • allowTakendown: When true, instead of throwing error for takendown accounts, a valid response with a narrow scoped token will be returned
  • authFactorToken: Used during the authentication process to handle Two-Factor Authentication

Examples

import gleam/http/request
import possum

let request =
  request.new()
  |> request.set_host("personal.data-server.pds")
  |> possum.create_session(
    did,
    "bsky-app-password",
    option.None,
    option.None
  )

Response

{
  "did": "string",
  "email": "string",
  "active": true,
  "didDoc": null,
  "handle": "string",
  "status": "takendown",
  "accessJwt": "string",
  "refreshJwt": "string",
  "emailConfirmed": true,
  "emailAuthFactor": true
}

Endpoint Docs: /xrpc/com.atproto.server.createSession

pub fn delete_record(
  request: request.Request(a),
  did: did.Did,
  collection collection: String,
  rkey rkey: String,
  swap_commit swap_commit: option.Option(String),
  swap_record swap_record: option.Option(String),
) -> request.Request(String)

Delete a repository record, or ensure it doesn’t exist. Requires auth, implemented by PDS.

  • collection: The NSID of the record collection.
  • repo: The handle or DID of the repo (aka, current account).
  • rkey: The Record Key.
  • swapCommit: Compare and swap with the previous commit by CID.
  • swapRecord: Compare and swap with the previous record by CID.

Examples

import gleam/http/request
import possum

let request =
  request.new()
  |> request.set_host("personal.data-server.pds")
  |> possum.authorized("access-token")
  |> possum.delete_record(
    did,
    collection: "target.collection.data",
    rkey: "wibble-wobble",
    swap_commit: option.None,
    swap_record: option.None,
  )

Response

{
  "commit": {
    "cid": "string",
    "rev": "string"
  }
}

Endpoint Docs: /xrpc/com.atproto.repo.deleteRecord

pub fn describe_repository(
  request: request.Request(a),
  did: did.Did,
) -> request.Request(a)

Get information about an account and repository, including the list of collections.

Examples

import gleam/http/request
import possum

let request =
  request.new()
  |> request.set_host("personal.data-server.pds")
  |> possum.describe_repository(did)

Response

{
  "did": "string",
  "didDoc": null,
  "handle": "string",
  "collections": [
    "string"
  ],
  "handleIsCorrect": true
}

Endpoint Docs: /xrpc/com.atproto.repo.describeRepo

pub fn get_plc_data(
  request: request.Request(a),
  did: did.Did,
) -> request.Request(a)

Get current PLC Data for the indicated DID, this returns information about a Decentralized Identifier (DID), including their handle and service endpoint.

PLC is a persistent global identifier system, stands for “Public Ledger of Credentials”.

Examples

import gleam/http/request
import possum

let request =
  request.new()
  |> possum.get_plc_data("did:plc:z72i7hdynmk6r22z27h6tvur")

Response

{
  "did": "string",
  "verificationMethods": {
    "atproto": "string"
  },
  "rotationKeys": [
    "string",
    "string"
  ],
  "alsoKnownAs": [
    "string"
  ],
  "services": {
    "atproto_pds": {
       "type": "string",
       "endpoint": "string"
  }
}

Documentation: DID PLC Directory

pub fn get_record(
  request: request.Request(a),
  did: did.Did,
  collection collection: String,
  rkey rkey: String,
  cid cid: option.Option(String),
) -> request.Request(a)

Get a single record from a repository. Does not require auth.

A record key (rkey) is used to name and reference an individual record withing the same collection of an repository.

You can use projects like Slingshot for easy access to cached data.

import gleam/http/request
import possum

let request =
  request.new()
  |> request.set_host("personal.data-server.pds") 
  |> possum.get_record(
    did,
    rkey: "3mn6n3lvibc2b",
    collection: "site.standard.document",
    cursor: option.None,
    cid: option.None,
  )

Response

{
  "cid": "string",
  "uri": "string",
  "value": null
}

Endpoint Docs: /xrpc/com.atproto.repo.getRecord Documentation: atproto.com

pub fn get_session_info(
  request: request.Request(a),
) -> request.Request(a)

Get information about the current auth session. Requires auth.

Examples

import gleam/http/request
import possum

let request =
  request.new()
  |> request.set_host("personal.data-server.pds")
  |> possum.authorized("access-token")
  |> possum.get_session_info

Response

{
  "did": "string",
  "email": "string",
  "active": true,
  "didDoc": null,
  "handle": "string",
  "status": "takendown",
  "emailConfirmed": true,
  "emailAuthFactor": true
}

Endpoint Docs: /xrpc/com.atproto.server.getSession

pub fn list_records(
  request: request.Request(a),
  did: did.Did,
  collection collection: String,
  limit limit: option.Option(Int),
  cursor cursor: option.Option(String),
  reverse reverse: option.Option(Bool),
) -> request.Request(a)

List a range of records in a repository, matching a specific collection.

Examples

import gleam/http/request
import possum

let request =
  request.new()
  |> request.set_host("personal.data-server.pds")
  |> possum.list_records(
    did,
    collection: "site.standard.document",
    limit: option.Some(3),
    cursor: option.None,
    reverse: option.None,
  )

Response

{
  "cursor": "string",
  "records": [
    {
      "cid": "string",
      "uri": "string",
      "value": null
    }
  ]
}

Endpoint Docs: /xrpc/com.atproto.repo.listRecords

pub fn list_standard_documents(
  request: request.Request(a),
  did: did.Did,
  limit limit: option.Option(Int),
) -> request.Request(a)

List published articles, blog posts and other content.

The site.standard.document lexicon provides metadata for individual documents. Including the document’s relation to a publication if applicable, a path to the document, and more information like a document’s complete contents.

This function os a wrapper around list_records.

Examples

import gleam/http/request
import possum

let request =
  request.new()
  |> request.set_host("personal.data-server.pds")
  |> possum.list_standard_documents(did, limit: option.None)

Documentation: standard.site

pub fn refresh_session(
  request: request.Request(a),
  refresh token: String,
) -> request.Request(a)

Refresh an authentication session. Requires auth using the ‘refreshJwt’ (not the ‘accessJwt’).

Examples

import gleam/http/request
import possum

let request =
  request.new()
  |> request.set_host("personal.data-server.pds")
  |> possum.refresh_session("refresh-token")

Response

{
  "did": "string",
  "email": "string",
  "active": true,
  "didDoc": null,
  "handle": "string",
  "status": "takendown",
  "accessJwt": "string",
  "refreshJwt": "string",
  "emailConfirmed": true,
  "emailAuthFactor": true
}

Endpoint Docs: /xrpc/com.atproto.server.refreshSession

pub fn resolve_handle(
  request: request.Request(a),
  handle handle: String,
) -> request.Request(a)

Resolves an atproto handle (hostname) to a DID. Does not necessarily bi-directionally verify against the the DID document.

You can use projects like Slingshot for easy access to cached data.

Examples

import gleam/http/request
import possum

let request =
  request.new()
  |> request.set_host("personal.data-server.pds")
  |> possum.resolve_handle("gleam.run")

Response

{
  "did": "string"
}

Endpoint Docs: /xrpc/com.atproto.identity.resolveHandle

pub fn resolve_well_known_did(
  request: request.Request(a),
  host host: String,
) -> request.Request(a)

Resolves a handle to a DID using a HTTPS /.well-known/ URL path, it looks for a file called “atproto-did” that contains the user DID.

Examples

import gleam/http/request
import possum

request.new()
|> possum.resolve_well_known_did("gleam.run")

Response

did:plc:k5vecqzf4d5mdvkcu3mx6l5g

Documentation: HTTPS well-known Method

Search Document