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. 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(String),
access_token token: String,
) -> request.Request(String)
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()
|> possum.authorized(access_token: "access-token")
assert request.headers != []
See also: create_session
pub fn create_record(
did: did.Did,
pds host: String,
collection nsid: nsid.Nsid,
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
option.Some(False)to skip Lexicon schema validation of record data,option.Some(True)to require it, or leave unset to validate only for known Lexicons.
Examples
import gleam/http/request
import possum/nsid
import possum/did
import possum
let assert Ok(did) = did.parse("did:plc:k5vecqzf4d5mdvkcu3mx6l5g")
let assert Ok(collection) = nsid.parse("wibble.wobble.woo")
let request =
possum.create_record(
did,
pds: "personal.data-server.pds",
collection:,
rkey: "wibble",
record: [],
swap_commit: option.None,
validate: option.None,
)
|> possum.authorized("access-token")
Response
{
"cid": "string",
"uri": "string",
"commit": {
"cid": "string",
"rev": "string"
},
"validationStatus": "valid"
}
Endpoint Docs: /xrpc/com.atproto.repo.createRecord
See also: did.parse, nsid.parse, authorized
pub fn create_session(
did: did.Did,
pds host: String,
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/did
import possum
let assert Ok(did) = did.parse("did:plc:ewvi7nxzyoun6zhxrhs64oiz")
let request =
possum.create_session(
did,
pds: "personal.data-server.pds",
app_password: "bsky-app-password",
allow_takendown: option.None,
auth_factor_token: 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
See also: did.parse, refresh_session
pub fn delete_record(
did: did.Did,
pds host: String,
collection nsid: nsid.Nsid,
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 possum/did
import possum/nsid
import possum
let assert Ok(did) = did.parse("did:plc:k5vecqzf4d5mdvkcu3mx6l5g")
let assert Ok(collection) = nsid.parse("wibble.wobble.woo")
let request =
possum.delete_record(
did,
pds: "personal.data-server.pds"
collection:,
rkey: "wibble-wobble",
swap_commit: option.None,
swap_record: option.None,
)
|> possum.authorized("access-token")
Response
{
"commit": {
"cid": "string",
"rev": "string"
}
}
Endpoint Docs: /xrpc/com.atproto.repo.deleteRecord
See also: did.parse, nsid.parse, create_session
pub fn describe_repository(
did: did.Did,
pds host: String,
) -> request.Request(String)
Get information about a user’s repository, including the list of collections.
Examples
import gleam/http/request
import possum/did
import possum
let assert Ok(did) = did.parse("did:plc:ewvi7nxzyoun6zhxrhs64oiz")
let request =
possum.describe_repository(did, pds: "personal.data-server.pds")
Response
{
"did": "string",
"didDoc": null,
"handle": "string",
"collections": [
"string"
],
"handleIsCorrect": true
}
Endpoint Docs: /xrpc/com.atproto.repo.describeRepo
pub fn get_blob(
did: did.Did,
cid cid: String,
pds host: String,
) -> request.Request(BitArray)
Get a blob associated with a given account. Returns the full blob as originally uploaded. Does not require auth; implemented by PDS.
Examples
import possum/did
import possum
let assert Ok(did) = did.parse("did:plc:k5vecqzf4d5mdvkcu3mx6l5g")
let request = possum.get_blog(did, "wibble-wobble", pds: "personal.data-server.pds")
Endpoint Docs: /xrpc/com.atproto.sync.getBlob
See also: did
pub fn get_plc_data(did: did.Did) -> request.Request(String)
Get current PLC Data for the indicated DID, this returns information about a Decentralized Identifier (DID), including their handle and PDS endpoint.
PLC is a persistent global identifier system, stands for “Public Ledger of Credentials”.
Examples
import possum/did
import possum
let assert Ok(did) = did.parse("did:plc:z72i7hdynmk6r22z27h6tvur")
let request = possum.get_plc_data(did)
// You can use this decoder to extract the server endpoint
let decoder =
decode.at(
["services", "atproto_pds", "endpoint"],
decode.string
)
Response
{
"did": "string",
"verificationMethods": {
"atproto": "string"
},
"rotationKeys": [
"string",
"string"
],
"alsoKnownAs": [
"string"
],
"services": {
"atproto_pds": {
"type": "string",
"endpoint": "string"
}
}
pub fn get_record(
did: did.Did,
pds host: String,
collection nsid: nsid.Nsid,
rkey rkey: String,
cid cid: option.Option(String),
) -> request.Request(String)
Get a single record from a repository. Does not require auth.
You can use projects like Slingshot for easy access to cached data.
import possum/did
import possum/nsid
import possum
let assert Ok(did) = did.parse("did:plc:k5vecqzf4d5mdvkcu3mx6l5g")
let assert Ok(collection) = nsid.parse("site.standard.document")
let request =
possum.get_record(
did,
pds: "slingshot.microcosm.blue",
collection:,
rkey: "mn6n3lvibc2b",
cursor: option.None,
cid: option.None,
)
Response
{
"cid": "string",
"uri": "string",
"value": null
}
Endpoint Docs: /xrpc/com.atproto.repo.getRecord
See also: did.parse, nsid.parse
pub fn get_session_info(
pds host: String,
) -> request.Request(String)
Get information about the current auth session.
Examples
import gleam/http/request
import possum
let request =
possum.get_session_info(pds: "personal.data-server.pds")
|> possum.authorized("access-token")
Response
{
"did": "string",
"email": "string",
"active": true,
"didDoc": null,
"handle": "string",
"status": "takendown",
"emailConfirmed": true,
"emailAuthFactor": true
}
Endpoint Docs: /xrpc/com.atproto.server.getSession
See also: create_session, refresh_session
pub fn list_records(
did: did.Did,
pds host: String,
collection nsid: nsid.Nsid,
limit limit: option.Option(Int),
cursor cursor: option.Option(String),
reverse reverse: option.Option(Bool),
) -> request.Request(String)
List a range of records in a repository, matching a specific collection.
Examples
import possum/did
import possum/nsid
import possum
let assert Ok(did) = did.parse("did:plc:ewvi7nxzyoun6zhxrhs64oiz")
let assert Ok(collection) = nsid.parse("site.standard.document")
let request =
possum.list_records(
did,
pds: "personal.data-server.pds",
collection:,
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
See also: did.parse, nsid.parse
pub fn put_record(
did: did.Did,
pds host: String,
collection nsid: nsid.Nsid,
rkey rkey: String,
record record: List(#(String, json.Json)),
swap_commit swap_commit: option.Option(String),
swap_record swap_record: option.Option(String),
validate validate: option.Option(Bool),
) -> request.Request(String)
Write a repository record, creating or updating it as needed. 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.
- swapRecord: Compare and swap with the previous record by CID.
- validate: Can be set to
option.Some(False)to skip Lexicon schema validation of record data,option.Some(True)to require it, or leave unset to validate only for known Lexicons.
Examples
import possum/did
import possum/nsid
import possum
let assert Ok(did) = did.parse("did:plc:k5vecqzf4d5mdvkcu3mx6l5g")
let assert Ok(collection) = nsid.parse("target.collection.data")
let request =
possum.put_record(
did,
pds: "personal.data-server.pds",
collection:,
rkey: "wibble-wobble",
record: [],
swap_commit: option.None,
swap_record: option.None,
validate: option.None,
)
|> possum.authorized("access-token")
Response
{
"cid": "string",
"uri": "string",
"commit": {
"cid": "string",
"rev": "string"
},
"validationStatus": "valid"
}
Endpoint Docs: /xrpc/com.atproto.repo.putRecord
See also: did.parse, nsid.parse, create_session
pub fn refresh_session(
token: String,
pds host: String,
) -> request.Request(String)
Refresh an authentication session. Requires auth using the ‘refreshJwt’ (not the ‘accessJwt’).
Examples
import possum
let request =
possum.refresh_session("refresh-token", pds: "personal.data-server.pds")
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
See also: create_session, get_session_info
pub fn resolve_handle(
handle: handle.Handle,
pds host: String,
) -> request.Request(String)
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 possum/handle
import possum
let assert Ok(handle) = handle.parse("gleam.run")
let request = possum.resolve_handle(handle, pds: "slingshot.microcosm.blue")
Response
{
"did": "string"
}
Endpoint Docs: /xrpc/com.atproto.identity.resolveHandle
See also: Did, handle.parse
pub fn resolve_well_known_did(
host host: String,
) -> request.Request(String)
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 possum
let request = possum.resolve_well_known_did(host: "gleam.run")
Response
did:plc:k5vecqzf4d5mdvkcu3mx6l5g
Documentation: HTTPS well-known Method