Skip to content

POST /api/v1/admin/orgs/:slug/teams/:teamId/members

This page is auto-generated from src/admin/routes.ts. Do not edit by hand — see docs/dev/docs-auto-sync.md.

:warning: Heuristic extraction — not a contract. Response shapes below are mined from c.json(...) literals in the handler via an AST walker. Computed fields, ternaries, and non-literal returns are shown as placeholders. Refer to the linked source file for the authoritative behaviour.

POST /api/v1/admin/orgs/:slug/teams/:teamId/members

Section titled “POST /api/v1/admin/orgs/:slug/teams/:teamId/members”

Requires the following capability(ies):

  • team_members:w

Other middleware observed on this route (heuristic):

  • requireCapability
  • adminBodyLimit

--- Team members (#564 Phase 1) -------------------------------------------

CRUD over the team_members composite-PK table. Adds the IDENTITY-grouping layer on top of the existing team-as-policy-grouping surface — a team has members, each member has a per-team role.

All four endpoints are gated on team_members:w. The admin-token / platform-admin caller carries the cap via role-defaults (owner + admin). Org member/viewer principals require the team_members membership lookup via canDoOnTeam — but the admin surface here is the platform-operator view: today’s caller IS effectively org-admin scoped through the URL :slug rebind, so requireCapability is the right gate. The dashboard-side per-team route in Phase 2 is where canDoOnTeam earns its keep.

:teamId is validated to belong to this org BEFORE any mutation runs — matches the cross-tenant guard the existing PATCH …/projects/:id/team endpoint enforces. Cross-org membership writes (team in org A, member in org B) are rejected as 404 from both sides:

  • team lookup → 404 if the team isn’t in this org.
  • member lookup → 404 if the member isn’t in this tenant.

Idempotency: POST returns 409 on the composite-PK collision (member already on this team). PATCH/DELETE return 404 if the row doesn’t exist. POST /api/v1/admin/orgs/:slug/teams/:teamId/members Body: { “member_id”: “<tenant_members.id>”, “role”: “admin” | “member” | “viewer” } Adds a tenant-member to a team with a per-team role.

{
"error": "Org not found"
}
{
"error": "Team not found for this org"
}
{
"error": "Invalid JSON body"
}
{
"error": "Body must be a JSON object"
}
{
"error": "member_id is required"
}
{
"error": "role must be 'admin', 'member', or 'viewer'"
}
{
"error": "Member not found for this org"
}
{
"error": "Member already on this team"
}
{
"team_id": <member-expr>,
"member_id": <member-expr>,
"role": <member-expr>,
"created_at": <call>
}
  • File: src/admin/routes.ts
  • Line: 5136