Skip to content

Spaces

Browse the spaces on this instance for moderation. These endpoints give operators access to spaces they are not members of, so they live in the admin API rather than the space XRPC API.

Listing spaces and reading their metadata and members requires spaces:read. Reading records and blobs requires spaces:manage-records, and each read is written to the event log as a space.moderator_read event.

const TOKEN = "hv_..."; // your API key
const headers = { Authorization: `Bearer ${TOKEN}` };
GET /admin/spaces

Every space on the instance, newest first.

ParamTypeRequiredDescription
limitnumbernoMax results per page (default 50, max 100)
cursorstringnoPagination cursor from a previous response
const response = await fetch("http://127.0.0.1:3000/admin/spaces?limit=20", {
headers,
});
const data = await response.json();

Response: 200 OK

{
"spaces": [
{
"id": "0b6c1f0e-...",
"uri": "at://did:web:happyview.example.com/space/com.example.forum/main",
"did": "did:web:happyview.example.com",
"authority_did": "did:web:happyview.example.com",
"creator_did": "did:plc:creator123",
"type": "com.example.forum",
"skey": "main",
"display_name": "Forum",
"description": null,
"read_policy": { "$type": "com.atproto.simplespace.defs#memberListPolicy" },
"write_policy": { "$type": "com.atproto.simplespace.defs#memberListPolicy" },
"app_access": { "$type": "com.atproto.simplespace.defs#open" },
"config": { "membership_public": false, "records_public": false },
"revision": "3k...",
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z"
}
],
"cursor": "50"
}

cursor is an offset. It is returned whenever a page is full, so the last page can be empty. revision is null until the space’s first commit.

GET /admin/spaces/{id}

A space’s metadata, its resolved member list (including members added through delegation), and the record count of each collection in it. {id} is the space’s id from List spaces.

const response = await fetch("http://127.0.0.1:3000/admin/spaces/0b6c1f0e-...", {
headers,
});
const data = await response.json();

Response: 200 OK

{
"space": { "id": "0b6c1f0e-...", "uri": "at://...", "...": "..." },
"members": [
{ "did": "did:plc:creator123", "read": true, "write": true }
],
"collections": [
{ "collection": "com.example.forum.post", "count": 42 }
]
}

Returns 404 Not Found if no space has that ID.

GET /admin/spaces/{id}/records

Records in a space, newest first. Requires spaces:manage-records.

ParamTypeRequiredDescription
repostringnoOnly records authored by this DID
collectionstringnoOnly records in this collection
limitnumbernoMax results per page (default 20, max 100)
cursorstringnoPagination cursor from a previous response
const response = await fetch("http://127.0.0.1:3000/admin/spaces/0b6c1f0e-.../records?collection=com.example.forum.post", {
headers,
});
const data = await response.json();

Response: 200 OK

{
"records": [
{
"uri": "at://did:web:happyview.example.com/space/com.example.forum/main/did:plc:abc/com.example.forum.post/3k...",
"did": "did:plc:abc",
"collection": "com.example.forum.post",
"rkey": "3k...",
"cid": "bafyrei...",
"indexed_at": "2026-01-01T00:00:00Z",
"record": { "...": "..." }
}
],
"cursor": "..."
}

cursor is returned whenever a page is full, so the last page can be empty. Each request is logged with the URIs of the records it returned.

GET /admin/spaces/{id}/blob

A blob referenced by a record in the space, fetched from its author’s PDS. The response body is the blob, with the content type the PDS reports. Requires spaces:manage-records.

ParamTypeRequiredDescription
cidstringyesThe blob CID
const response = await fetch("http://127.0.0.1:3000/admin/spaces/0b6c1f0e-.../blob?cid=bafkrei...", {
headers,
});
const blob = await response.blob();

Returns 404 Not Found if no record in the space references the blob, and 502 Bad Gateway if the author’s PDS cannot serve it.

GET /admin/spaces/migration-status

How far each space’s repositories have moved from HappyView-hosted copies to their authors’ PDSes, and which PDSes support spaces. Requires spaces:read.

Response: 200 OK

{
"spaces": [
{ "spaceId": "0b6c1f0e-…", "type": "com.example.forum", "skey": "main", "polyfill": 12, "migrating": 3, "native": 40 }
],
"awaitingAuthorization": 5,
"detection": [
{ "pds": "https://pds.example.com", "supported": true, "tier": "descriptor", "missing": [], "checkedAt": "2026-10-01T12:00:00Z" }
]
}
  • polyfill, migrating and native count the space’s repositories by where they’re hosted: still on HappyView, moving, or on the author’s PDS. A space with no repositories is not listed.
  • awaitingAuthorization counts accounts whose repositories are still on HappyView and who haven’t signed in with a session granting space: access, so they can’t move yet.
  • detection is what HappyView last found out about each PDS’s support for spaces, and what it’s missing. tier says how it found out: descriptor (the PDS lists its own methods), probe (inferred from how it answers a method that needs auth) or unreachable (HappyView couldn’t reach the PDS, which says nothing about its support).