Skip to main content
Driftstack DRIFTSTACK

Teams & RBAC

Driftstack supports team accounts where multiple users share a single billing entity. This page covers the invite flow, the member vs. admin roles, and how a team member calls API endpoints against the owner's resources.

Vocabulary

Invite flow

# 1. Owner sends an invite
POST /v1/team/invites
Authorization: Bearer ds_live_owner_…
Content-Type: application/json

{ "email": "[email protected]", "role": "admin" }

→ 202 Accepted
{ "message": "Invite sent. The invitee can accept via the email link." }

# 2. Owner can list pending invites
GET /v1/team/invites
Authorization: Bearer ds_live_owner_…

→ 200 OK
{
  "data": [
    {
      "id": "inv_…",
      "owner_account_id": "acc_owner_…",
      "invitee_email": "[email protected]",
      "role": "admin",
      "expires_at": "2026-05-19T13:00:00.000Z",
      "invited_by_account_id": "acc_owner_…",
      "accepted_at": null,
      "created_at": "2026-05-12T13:00:00.000Z"
    }
  ]
}

# 3. Invitee redeems the token from the email
POST /v1/team/invites/accept
Authorization: Bearer ds_live_invitee_…
Content-Type: application/json

{ "token": "<plaintext token from the email link>" }

→ 200 OK
{
  "membership": {
    "id": "mem_…",
    "owner_account_id": "acc_owner_…",
    "member_account_id": "acc_invitee_…",
    "member_email": "[email protected]",
    "role": "admin",
    "invited_at": "2026-05-12T13:00:00.000Z",
    "accepted_at": "2026-05-12T13:15:00.000Z",
    "invited_by_account_id": "acc_owner_…"
  }
}

Acceptance posts the plaintext token from the email — there is no /v1/team/invites/<id>/accept endpoint. The invite row itself can't be revoked via the API today; the invite simply expires.

Listing + removing members

# Owner lists their team
GET /v1/team/members
Authorization: Bearer ds_live_owner_…

→ 200 OK
{
  "data": [
    {
      "id": "mem_…",
      "owner_account_id": "acc_owner_…",
      "member_account_id": "acc_member_…",
      "member_email": "[email protected]",
      "role": "admin",
      "invited_at": "2026-05-12T13:00:00.000Z",
      "accepted_at": "2026-05-12T13:15:00.000Z",
      "invited_by_account_id": "acc_owner_…"
    }
  ]
}

# Owner removes a membership by membership id (mem_…, NOT account id)
DELETE /v1/team/members/mem_…
Authorization: Bearer ds_live_owner_…

→ 204 No Content

The DELETE route takes the mem_ membership id, not an acc_ account id. Transferring ownership of an account is a support-ticket operation today.

Teams I am on

GET /v1/team/owners
Authorization: Bearer ds_live_member_…

→ 200 OK
{
  "data": [
    {
      "owner_account_id": "acc_owner_…",
      "role": "admin",
      "membership_id": "mem_…"
    }
  ]
}

The mirror of /v1/team/members — the latter lists members of my team, this one lists teams I am on. Use the returned owner_account_id with the X-Driftstack-Account header on subsequent requests to act on that team's resources.

X-Driftstack-Account: acting on a team owner's resources

Team members read + write the owner's resources by passing the owner's account id in the X-Driftstack-Account request header. The server validates the caller has a valid membership on that owner before routing the request.

# List the team owner's sessions
GET /v1/sessions
Authorization: Bearer ds_live_member_…
X-Driftstack-Account: acc_owner_…

SDK shortcut: effectiveAccount

The official SDKs send the header for you — construct a client scoped to a workspace and every request carries it. Omit it for your own account.

// TypeScript
const client = new Driftstack({ apiKey, effectiveAccount: 'acc_owner_…' });

# Python
client = Driftstack(api_key, effective_account="acc_owner_…")

// Go
client := driftstack.New(apiKey, driftstack.WithEffectiveAccount("acc_owner_…"))

The desktop app exposes the same control as a workspace switcher in the profiles hub. Note: reads resolve against the workspace, but session launch against an owner's profile is an owner-only action today.

Role enforcement: reads are allowed for both member and admin. Writes (e.g. POST /v1/sessions, POST /v1/webhooks, POST /v1/webhooks/<id>/rotate-secret) require admin; members get 403. See /api-reference for the per-endpoint gate.

What admins cannot do

Audit trail

Team mutations (invite sent, invite accepted, member removed) write entries on the owner's audit log. Read via GET /v1/account/audit-log?action=team.* — see /docs/audit-log.

Support

Team setup or ownership transfers: [email protected]. RBAC + audit questions: [email protected].