Skip to content

Access Control Reference

Capgo uses role-based access control (RBAC) to manage what each team member can do. Roles are organized by scope — from the entire organization down to a single bundle.

For a visual walkthrough of managing members in the dashboard, see Organization.


Every role belongs to a scope that determines what resource it grants access to.

ScopeApplies toExample use case
OrganizationThe entire org and all its appsYour co-founder gets Super Admin; your accountant gets Billing Manager
AppA single app and its channelsA contractor working on one app gets App Developer
ChannelA single channel within an appA QA engineer only manages the staging channel
BundleA single bundle versionA reviewer needs read access to one specific release

A member can hold one role per scope target — for example, one org role, one role on App A, and a different role on App B.


These roles are assigned when inviting a member. They grant access across the entire organization.

RoleInternal nameDescription
Super Adminorg_super_adminOwner-equivalent. Full control including deleting the org, managing billing, and transferring apps. Automatically granted to the org creator.
Adminorg_adminFull administration — manage members, apps, channels. Cannot delete the org, update billing, transfer apps, or promote users to Super Admin.
Billing Managerorg_billing_adminBilling-only access: view and update billing info, invoices, and billing audit logs. No access to apps or members.
Memberorg_memberRead-only access to the org and all its apps.
PermissionDescriptionSuper AdminAdminBilling ManagerMember
org.readView the organization
org.update_settingsEdit org name, logo, management email
org.deletePermanently delete the organization
org.read_membersView the member list
org.invite_userInvite new members
org.update_user_rolesChange member roles (Admin cannot promote to Super Admin — blocked by role hierarchy)
org.read_billingView billing info and current plan
org.update_billingUpdate payment method and plan
org.read_invoicesView invoices
org.read_auditView organization activity log
org.read_billing_auditView billing-specific audit log

Scoped to a single app. Use these when a team member should only work on one app, not the whole organization.

RoleInternal nameDescription
App Adminapp_adminFull control of one app — channels, devices, user roles for the app. Cannot delete or transfer the app (those are org-level operations).
App Developerapp_developerUpload bundles, manage devices, trigger native builds, update channel settings. No deletion, no app settings changes, no channel creation.
App Uploaderapp_uploaderRead access + upload new bundle versions.
App Readerapp_readerRead-only — stats, bundles, channels, logs, devices.
PermissionDescriptionApp AdminApp DeveloperApp UploaderApp Reader
app.readView app details, stats, and metadata
app.update_settingsEdit app settings
app.read_bundlesView the list of uploaded bundles
app.upload_bundleUpload a new bundle version
app.create_channelCreate a new channel
app.read_channelsView channels
app.read_logsView update delivery logs
app.manage_devicesAssign, override, or unlink devices
app.read_devicesView the device list
app.build_nativeTrigger a native cloud build
app.read_auditView app-level activity log
app.update_user_rolesManage app-scoped role assignments
bundle.deleteDelete a bundle

Scoped to a single channel. Useful for giving targeted access to a specific release channel.

RoleInternal nameDescription
Channel Adminchannel_adminFull control of one channel: settings, promote/rollback bundles, manage forced devices.
Channel Viewerchannel_readerRead-only — current bundle, history, forced devices, audit log.
PermissionDescriptionChannel AdminChannel Viewer
channel.readView the channel and its current bundle
channel.update_settingsEdit channel settings (platform toggles, update policy…)
channel.deleteDelete the channel
channel.read_historyView bundle assignment history
channel.promote_bundleSet the active bundle on the channel
channel.rollback_bundleRoll back to a previous bundle
channel.manage_forced_devicesForce specific devices to this channel
channel.read_forced_devicesView the list of forced devices
channel.read_auditView channel activity log

Scoped to a single bundle version. Rarely needed — most teams use app-level roles instead.

RoleInternal nameDescription
Bundle Adminbundle_adminRead, update metadata, and delete a specific bundle.
Bundle Viewerbundle_readerRead-only access to a specific bundle.

In the dashboard, channel access is determined by the user’s app role by default. For more granular control, you can override specific channel permissions per user or group without changing their app role.

Overrides are configured from the app’s Access tab by clicking the channel permissions button (shield icon) next to a user. See Organization — Overriding channel permissions for a visual walkthrough.

PermissionDescriptionDefault behavior
ReadView the channel and its current bundleInherited from app role
HistoryView the bundle assignment historyInherited from app role
Associate bundleSet or change the active bundle on the channelInherited from app role

Each permission can be set to:

  • Default — inherit from the app role (the default)
  • Allow — explicitly grant, regardless of the app role
  • Deny — explicitly block, regardless of the app role

This lets you, for example, give an App Reader the ability to associate bundles on the staging channel without promoting them to App Developer.


Roles form a hierarchy. A parent role inherits all permissions of its children. This means an org_admin can do everything an app_admin can, which in turn can do everything a channel_admin can, and so on.

Super Admin (org_super_admin)
└── Admin (org_admin)
└── App Admin (app_admin)
├── App Developer (app_developer)
│ └── App Uploader (app_uploader)
│ └── App Reader (app_reader)
├── Bundle Admin (bundle_admin)
│ └── Bundle Viewer (bundle_reader)
└── Channel Admin (channel_admin)
└── Channel Viewer (channel_reader)

How it works in practice:

  • An Admin at the org level can do everything an App Admin can, on every app in the org.
  • An App Admin on a specific app can do everything a Channel Admin can, on every channel in that app.
  • An App Developer can do everything an App Uploader can, plus more.

The hierarchy only flows downward — a channel_admin never gains org-level permissions, even if they also hold an app-level role.


Instead of assigning roles to each user individually, you can create groups and assign roles to the group. Every member of the group inherits those roles automatically.

  • A group belongs to one organization — it cannot span multiple orgs.
  • Groups can hold role bindings at any scope: org, app, channel, or bundle. For example, a group can be assigned the App Developer role on App A and the Channel Admin role on the staging channel of App B.
  • When a user’s permissions are evaluated, all their group memberships are resolved transparently. If any of their groups grants the required permission, access is allowed.
  • A user can belong to multiple groups, and permissions from all groups are additive.
  • Group-based permissions only apply to user principals — API keys do not inherit group roles.
ScenarioWithout groupsWith groups
5 QA engineers need Developer access to 3 apps15 individual role bindings1 group + 3 role bindings
Someone joins the QA teamAdd 3 role bindings manuallyAdd them to the group
Someone leaves the QA teamRemove 3 role bindings manuallyRemove them from the group

All group endpoints require authentication and are served under /private/groups.

Terminal window
curl -X GET "https://api.capgo.app/private/groups/<ORG_ID>" \
-H "authorization: <API_KEY>"

Requires org.read_members permission.

Terminal window
curl -X POST "https://api.capgo.app/private/groups/<ORG_ID>" \
-H "authorization: <API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"name": "QA Team",
"description": "Quality assurance engineers"
}'

Requires org.update_user_roles permission (Super Admin or Admin).

Terminal window
curl -X PUT "https://api.capgo.app/private/groups/<GROUP_ID>" \
-H "authorization: <API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"name": "QA Team",
"description": "Updated description"
}'
Terminal window
curl -X DELETE "https://api.capgo.app/private/groups/<GROUP_ID>" \
-H "authorization: <API_KEY>"

Deleting a group also removes all its role bindings. Members are not deleted from the organization.

Terminal window
curl -X GET "https://api.capgo.app/private/groups/<GROUP_ID>/members" \
-H "authorization: <API_KEY>"
Terminal window
curl -X POST "https://api.capgo.app/private/groups/<GROUP_ID>/members" \
-H "authorization: <API_KEY>" \
-H "Content-Type: application/json" \
-d '{ "user_id": "<USER_UUID>" }'

The user must already be a member of the organization. Adding an existing member is a no-op.

Terminal window
curl -X DELETE "https://api.capgo.app/private/groups/<GROUP_ID>/members/<USER_UUID>" \
-H "authorization: <API_KEY>"

Terminal window
curl -X GET "https://api.capgo.app/organization/members" \
-H "authorization: <API_KEY>" \
-H "Content-Type: application/json" \
-d '{ "orgId": "<ORG_ID>" }'

Response:

[
{
"uid": "user-uuid",
"email": "alice@example.com",
"image_url": "https://...",
"role": "org_admin",
"is_tmp": false
}
]
Terminal window
curl -X POST "https://api.capgo.app/organization/members" \
-H "authorization: <API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"orgId": "<ORG_ID>",
"email": "bob@example.com",
"invite_type": "org_admin"
}'

Accepted values for invite_type:

ValueRole assigned
org_super_adminSuper Admin
org_adminAdmin
org_billing_adminBilling Manager
org_memberMember
Terminal window
curl -X DELETE "https://api.capgo.app/organization/members" \
-H "authorization: <API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"orgId": "<ORG_ID>",
"email": "bob@example.com"
}'

Terminal window
npx @capgo/cli organization list --apikey <API_KEY>
Terminal window
npx @capgo/cli organization members <ORG_ID> --apikey <API_KEY>

The built-in roles cover most team structures. Custom role creation is on our roadmap — if this is something your team needs, reach out to us. Your use case will directly help us prioritize this feature.