Skip to content

Docs / Teams & roles

Teams & roles

Owner, admin, member and viewer: what each can do, how membership is granted, and the last-owner rule.

An account is the tenant — your personal namespace or a GitHub organisation. A user is a person. A membership joins the two and carries exactly one role.

The four roles

Role Can
viewer Read everything: audit log, repos, tasks, runners, billing, dashboards. No writes.
member Viewer, plus: dispatch tasks, write to the knowledge base, manage artifacts and dashboards, and manage their own model keys and prompt.
admin Member, plus: runners, billing, integrations, secrets, donations, org members, and org/repo prompts.
owner Everything account-scoped: the account itself, repos, issues, PRs, sessions and webhooks.

The ceiling is applied once, when your credential is resolved. Individual endpoints then check a scope — there is no second, divergent role check further down that could disagree with this table.

Note what an owner does not get: cross-account platform reads. Those are staff-only and are excluded from every role ceiling by construction, so no customer owner can quietly acquire a view of another tenant.

How membership is created

Membership comes from the GitHub App installation, and it is least-privilege on every ambiguity:

  • Your own personal namespaceowner.
  • An organisation where GitHub reports you as an org owner → owner.
  • An organisation where you are a plain member, or where we cannot read your org role at all → member.

The write is elevate-only: signing in can raise your role, never lower it. Every elevation is written to the audit log.

Adding someone to an org

curl -X POST https://api.developerz.ai/v1/org/members \
  -H "Authorization: Bearer …" \
  -H "content-type: application/json" \
  -d '{"login":"octocat","role":"member"}'

Scope: write:members (admin or owner).

This is "add an existing member", not "send an invite". There is no invitation email and no pending-invite state. The person must have signed in to developerz.ai at least once; if the login is not a registered user the API returns 404 with exactly that reason. Have them sign in with GitHub first, then add them.

The call also requires a user session. A personal access token carries scopes but no membership role, so PAT callers get 403 here — member management is a thing a person does, not a thing a script does on their behalf.

Method Path Scope
GET /v1/org/members read:account
POST /v1/org/members write:members
PATCH /v1/org/members/:userId write:members
DELETE /v1/org/members/:userId write:members

The three rules that govern changes

Enforced inside the database transaction, with the row locked, so two simultaneous requests cannot slip past each other:

  1. Authority. You may always act on yourself. An owner may act on anyone. Anyone else may act only on someone strictly lower-ranked — an admin cannot modify another admin, or an owner.
  2. No escalation. An owner may grant up to owner. Anyone else may grant only strictly below their own rank, so admins cannot mint admins or owners.
  3. Last owner. Removing or demoting the only remaining owner is refused. An account without an owner is an account nobody can recover.

Every successful change is audited as org_member.invited, .role_changed or .removed.

Switching between accounts

If you belong to more than one account, GET /v1/me returns your memberships and POST /v1/me/active-account switches the active one (scope: write:account, user session required). The switch is audited.

In the dashboard the organisation lives in the URL — /org/<login>/… — so which tenant you are looking at is a property of the page you are on, not hidden server-side state you can lose track of.

Requests may also carry an X-Dz-Account header. It is never trusted as given: it is resolved and checked against your memberships before it becomes the tenant for that request.

Per-user resources

Some things are deliberately personal rather than shared:

  • Model keys. An org-pool key is visible to everyone in the account; a personal key is visible only to you. When a run has an acting user, their own keys rank first and the org pool is the fallback. Autonomous work — a webhook with no human behind it — can only see org keys.
  • System prompts. Layers stack platform → org → repo → user. Org and repo layers need write:prompts (admin); your own layer needs write:self:prompt (member).

SSO

Enterprise SSO is available on enterprise contracts, routed by verified email domain. A per-organisation OIDC provider ("bring your own IdP") also exists and is enabled per account.

SCIM is not implemented. SSO authenticates people who already have an account; it does not provision new ones. An SSO identity with no matching user is bounced to the dashboard to onboard through GitHub first. If you need directory provisioning, talk to us — do not plan around it existing today.

  • Billingwrite:billing is an admin scope.
  • REST API — the full scope list.
  • Security — what the agent itself may do, which is a separate question.