List teams (paginated; optional ancestor filter)
GET /teams
Returns every team the caller can see, ordered by name. When
ancestor is supplied, returns only that team and every team
in its closure (descendants), which lets the upload modal
scope a picker to “teams under Aurora R&D” without N+1.
Requires teams.read.
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Query Parameters
Section titled “Query Parameters ”Responses
Section titled “ Responses ”A page of teams
object
object
URL-friendly identifier, unique per origin server. Used in display and (eventually) federation actor URIs.
Example
aurora-rndExample
Aurora R&DSet on rows mirroring a federated team. NULL = locally owned.
The team’s picture (#982) — fetch it from
/assets/{hero_asset_id}/variants/col. NULL means the
client falls back to the team’s initials tile.
THIS IS THE RENDER ANSWER, NOT THE STORED SETTING. The
server re-derives it on every read, and it is absent
whenever the chosen asset no longer qualifies: set to
restricted, moved to another team, soft-deleted, or still
missing its col rendition. The stored pointer survives all
of those, so restoring the asset brings the picture back
without an admin re-picking it — but until then the wire
says “no hero” and the client paints initials.
One field rather than the setting/render pair Collection
carries, because the two cannot disagree PER READER here.
ADR 0088 gates a representative image per viewer; #982
narrows that for a team, because the followed-teams rail is
a navigation strip and a strip that shows some teams’
pictures and not others depending on who is looking is noise
rather than security. A team hero is admissible only if it
is public AND owned by that team — visible to everyone or
to no one — so a single field cannot be misread.
It does NOT federate: a local asset id names something that exists only on this server.
Direct parent teams (single hop). Empty for root teams.
Closure-walked ancestors live behind the listTeams
ancestor filter; this field is just the edges out of
the current node.
object
Direct memberships. Present on listTeams — the directory
card shows it (#684) — and ABSENT from getTeam.
The asymmetry is deliberate and is about staleness, not
taste. getTeam reads through an LRU that only the
team-row and parent-edge endpoints invalidate; adding a
membership does not, and never needed to, because nothing
membership-shaped was cached. A count served from that
entry would go stale the first time somebody joined. The
list path is uncached, so it can carry the number honestly.
A team page that wants the count reads
GET /teams/{id}/members, which it already fetches for the
member strip.
Live (non-soft-deleted) assets carrying this team_id — the
directory card’s “how much is in here” hint (#684). Present
on listTeams only, for the same caching reason as
member_count.
NOT visibility-filtered, deliberately. It counts assets
whose fields the caller may not read. That discloses
nothing new: this operation needs teams.read, so the
caller is signed in, and the authenticated asset predicate
already hands them restricted rows as placeholders — the
same number is reachable by paging
/assets?team_id=X. Filtering it would make the card
disagree with the page it links to.
Authentication required, missing, or invalid
object
Human-readable error summary
Example
the request could not be completedExample
{ "error": "authentication required: sign in and retry with a valid session or API token"}Authenticated but missing required capabilities
object
Human-readable error summary
Example
the request could not be completedUnexpected server error
object
Human-readable error summary
Example
the request could not be completed