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 namespace →
owner. - 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:
- 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.
- 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.
- 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 needwrite:prompts(admin); your own layer needswrite: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.