Getting started
atproto_client is transport-agnostic: every function takes a Client,
which is nothing more than a send function you provide. You pick the HTTP
backend (erlang httpc, JS fetch, a test stub); the package never performs
IO on its own.
1. Wire a Client
On the Erlang target, gleam_httpc
works well:
import atproto/xrpc
import gleam/httpc
import gleam/string
fn client() -> xrpc.Client {
xrpc.Client(send: fn(req) {
httpc.send_bits(req)
|> result.map_error(fn(error) {
case error {
httpc.ResponseTimeout -> xrpc.Timeout
httpc.FailedToConnect(_, _) ->
xrpc.ConnectionFailed(string.inspect(error))
_ -> xrpc.Other(string.inspect(error))
}
})
})
}
Transport failures are structured (TransportError): your backend maps its
own error type onto InvalidUrl/Timeout/ConnectionFailed/Other, and
callers can branch on them instead of string-matching.
For a browser app, use
atproto_browser instead: it is
the same shapes rebuilt around async fetch and WebCrypto, not a drop-in
swap of the send function.
2. Resolve an identity
atproto/identity resolves a handle or DID to its PDS via a
Slingshot-compatible resolver (identity.default_resolver points at
slingshot.microcosm.blue):
import atproto/identity
let assert Ok(pds) =
identity.resolve_pds(client(), identity.default_resolver, "someone.bsky.social")
3. Call XRPC
atproto/xrpc has get, post_json, and BitArray variants for blobs. For
repo CRUD, atproto/repo wraps the com.atproto.repo.* endpoints,
including cursor-following list_records and upload_blob:
import atproto/repo
import gleam/dynamic/decode
let rows =
repo.list_records(
client(),
pds,
access_token,
did,
"app.bsky.feed.post",
decode.dynamic,
)
4. Authenticate
Two options:
atproto/auth: app-password session creation, the simplest way to get an access token for scripts and tooling.atproto/oauth/*: the full atproto OAuth client flow for a confidential client (discovery viaoauth/metadata, PAR + PKCE + DPoP viaoauth/flow, token exchange and refresh viaoauth/tokens). Start at theatproto/oauth/flowmodule docs;oauth/runnerexecutes the sans-io flow against yourClient.
Going further
- Generated typed clients:
atproto_codegenemits one typed function per lexicon query/procedure on top ofatproto/xrpc. - Backlinks:
atproto/constellationqueries the microcosm backlink index. - Every module carries doc comments with the finer details; this guide is only the map.