Skip to content

Overview

Spaces are containers for permissioned data in atproto. Unlike regular public records that live in a user’s repo, space records are gated by membership — only members can read or write data within a space.

A space is identified by three components:

  • Space DID: the DID of the space’s authority. Spaces created through HappyView use HappyView’s service identity DID. See Space authority.
  • Type: the space type as an NSID, describing the modality (e.g. a forum, a group chat, a photo album)
  • Space key (skey): a short string differentiating multiple spaces of the same type

These form the space URI: at://<space-did>/space/<type>/<skey>

A space record adds three more components to the URI: the author’s DID, the collection NSID, and the record key:

at://<space-did>/space/<type-nsid>/<skey>/<author-did>/<collection>/<rkey>

In HappyView, spaces are gated behind the feature.spaces_enabled instance setting. Enable it in the dashboard under Settings or via the admin API:

const response = await fetch("http://127.0.0.1:3000/admin/settings/feature.spaces_enabled", {
method: "PUT",
headers: {
"Authorization": `Bearer ${TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ value: "true" }),
});

When disabled, all space endpoints return a 404 error with FeatureDisabled as the error code.

Space endpoints are split across two namespaces:

  • com.atproto.space.*: protocol-level routes (queries, data, credentials, sync)
  • com.atproto.simplespace.*: management routes (create/update/delete spaces, membership)

The dev.happyview.space.* aliases are deprecated and kept until v3. Most endpoints take DPoP authentication or cookie-based session auth. Read and sync endpoints also take a space credential, and the notify endpoints take service auth.

EndpointMethodDescription
com.atproto.simplespace.createSpacePOSTCreate a space
com.atproto.simplespace.getSpaceGETGet a space and its policies
com.atproto.space.listSpacesGETList spaces by membership
com.atproto.simplespace.updateSpacePOSTUpdate a space
com.atproto.simplespace.deleteSpacePOSTDelete a space
com.atproto.simplespace.putMemberPOSTAdd a member or set their access
com.atproto.simplespace.removeMemberPOSTRemove a member
com.atproto.simplespace.listMembersGETList resolved members
com.atproto.space.createRecordPOSTCreate a record (auto-generated rkey)
com.atproto.space.putRecordPOSTWrite a record
com.atproto.space.getRecordGETGet a record
com.atproto.space.listRecordsGETList records
com.atproto.space.deleteRecordPOSTDelete a record
com.atproto.space.applyWritesPOSTBatch write operations
com.atproto.space.getLatestCommitGETGet per-user signed commit
com.atproto.space.getRepoGETExport a user’s repo as a CAR file
com.atproto.space.listRepoOpsGETList record operation log entries
com.atproto.space.listReposGETList the space’s writer set
com.atproto.space.getBlobGETGet a blob from a space
com.atproto.space.listBlobsGETList the blobs a repo’s records reference
com.atproto.space.getDelegationTokenGETGet a delegation token (step 1 of credentials)
com.atproto.space.getSpaceCredentialPOSTExchange it for a space credential (step 2)
com.atproto.space.registerNotifyPOSTRegister a syncer for write notifications
com.atproto.space.unregisterNotifyPOSTWithdraw a registration
com.atproto.space.notifyWritePOSTReport a repo’s new commit
com.atproto.space.notifySpaceDeletedPOSTPush a space-deleted notification
dev.happyview.space.createInvitePOSTCreate an invite (HappyView extension)
dev.happyview.space.acceptInvitePOSTAccept an invite (HappyView extension)
dev.happyview.space.revokeInvitePOSTRevoke an invite (HappyView extension)
dev.happyview.space.listInvitesGETList invites (HappyView extension)

com.atproto.simplespace.addMember is a deprecated form of putMember, kept until v3. See Legacy addMember.

A space’s creator administers it: they update and delete the space and manage its members and invites.

Instance operators can browse any space for moderation through the admin spaces API without being members. Each read of a space’s contents is recorded in the event log.

Two independent policies decide who can use the space. See Policies.

  • The read policy decides who can obtain a space credential to read the whole space.
  • The write policy decides whose writes the space tracks and forwards to syncers.

Each policy is member-list (the default), public, or managing-app.

App access controls which third-party apps can obtain credentials: open (the default) or an allow list of OAuth client IDs.

Under member-list policies, each member has two flags, read and write, set independently. The creator is automatically added with both. See Members.

Spaces also support delegation: adding another space as a member, which grants its members access to this space.

HappyView implements atproto Proposal 0016 (Permissioned Data) with some HappyView-specific extensions.

  • Namespace split: com.atproto.space.* for protocol routes, com.atproto.simplespace.* for management
  • Space authority: new spaces use the instance’s DID, published with #atproto_space_host and #atproto_space entries
  • Read and write policies: memberListPolicy, publicPolicy, managingAppPolicy
  • App access: open, allowList
  • Member list: putMember with independent read and write flags
  • Delegation tokens: getDelegationToken (GET, 60-second TTL, single use), or tokens signed by the account’s own key
  • Space credentials: atproto-space-credential+jwt, ES256, 10-minute TTL, bound to a key with cnf.kid and used with RFC 9421 HTTP Message Signatures
  • Credential revocation: notifyCredentialRevoked sent to hosts of repos in the space
  • Deniable commit signatures: user signs context (space + author + rev + random IKM), not content hash
  • LtHash: homomorphic set-hash (2048-byte state, 1024 uint16 lanes, BLAKE3 XOF)
  • SignedCommit: versioned commit struct (ver: 1) with hash, ikm, sig, mac, rev
  • Record operation log: listRepoOps returns the oplog for sync (values inlined by default, excludeValues to opt out)
  • Latest commit: getLatestCommit returns the signed commit for a user in a space
  • Repo export: getRepo exports a user’s repo as a CAR v1 file (signedCommit + DRISL index)
  • Sync: registerNotify by service identifier, notifyWrite in both directions, listRepos from the writer set with a space-wide revision
  • Space-scoped blobs: getBlob, listBlobs

HappyView extensions (not in the protocol spec)

Section titled “HappyView extensions (not in the protocol spec)”
  • Invite system: createInvite, acceptInvite, revokeInvite, listInvites (under dev.happyview.space.*)
  • isDelegation on members: allows spaces to be members of other spaces
  • displayName, description on spaces: human-readable metadata
  • config object: membership_public, plus arbitrary extra fields. records_public is deprecated and not enforced.
  • read_self access: limits a member’s reads to their own records