Moonborn — Developers
RBAC role matrix
The seven built-in roles, their permissions, and how to assign or change them. Custom roles on Enterprise.
Moonborn ships seven built-in roles. Custom roles are an Enterprise feature; the matrix below is the v1 default.
Built-in roles
| Role | personas | chat | billing | config | webhooks | audit | members |
|---|---|---|---|---|---|---|---|
owner | RW | RW | RW | RW | RW | R | RW |
admin | RW | RW | RW | RW | RW | R | RW |
editor | RW | RW | — | R | R | — | — |
viewer | R | R | — | R | R | — | — |
api-only | scoped | scoped | — | scoped | scoped | — | — |
billing | — | — | RW | — | — | — | — |
auditor | — | — | R | R | R | R | R |
scoped = honors the API key's scope list. api-only users can't
sign in to the product UI.
Assign a role at invite
await client.memberships.inviteMember({
email: 'designer@acme.co',
role: 'editor',
workspaceId: 'ws_...',
});Change an existing role
await client.memberships.updateMembership({
id: 'mem_...',
role: 'admin',
});Every role change writes an audit-log row with actor + timestamp.
Custom roles (Enterprise)
Define your own resource × action matrix:
await client.roles.createCustomRole({
workspaceId: 'ws_...',
name: 'persona-reviewer',
permissions: [
'personas:read',
'personas:audit:run',
'audit:read',
],
});Permissions follow the <resource>:<action> pattern. The full action
list lives at GET /v1/roles/actions.
Why no nested groups
We intentionally don't ship LDAP-style group nesting in v1. A flat role list is easier to reason about; SCIM provisioning maps your IdP groups onto Moonborn roles 1:1.
Tier
Built-in roles: Pro and up. Custom roles: Enterprise.