Skip to content
GitmoapdocsBeta
Guide· How do I…?

Custom roles

Overview

The five built-in roles — Guest, Reporter, Developer, Maintainer and Owner — cover most of what people do. When they do not, your organisation can define its own: a custom role starts from a built-in role and adds or removes individual permissions. Developer, but without deleting branches. Reporter, plus the audit log. Someone from support who reads and files issues and never sees the code.

You define a role once, for the whole organisation, and give it the way you give a built-in role — to a person, a service account or a team, on any group or repository. What the role allows applies there and everywhere beneath it.

Quick start

Quick start3 steps

Define a role that reads and files issues without reading code, and give it to someone

You’ll need Owner of the organisation.
  1. Define it: gitmoap roles create-role --group-id acme --slug stakeholder --name Stakeholder --base-role guest --added '["issues.read","issues.create"]'.

  2. Give it: gitmoap access create-repo-access-grants --repo-id acme/billing --subjects '[{"principal":"<user-id>"}]' --role '{"custom":"<role-id>"}'.

  3. They can now open the repository, read its issues and file new ones — and not browse its code.

Before you start

  • Owner of the organisation to define, change or delete a role.Changing a role changes what everyone who holds it can do, everywhere it is given, so it stays with the people who own the organisation.
  • Anyone in the organisation can see its rolesand where they are used. Someone whose only access is to one repository sees none of this.
  • Giving a custom role is giving access.It needs access.manage where you give it, and you can only give a role whose every permission you hold yourself — see Access.
  • A token with the right scope, if you are using the CLI or the API: role:read to list and read, which comes with read_api; role:manage to define, change and delete, which no bundle includes — ask for it by name.

How it works

A role is a base, plus additions, less removals. The base is Guest, Reporter, Developer or Maintainer. Add permissions to it or remove them from it, by key — code.push, issues.create, audit.read. The full list, with what each permission needs, is in the permission catalogue: gitmoap access list-access-permissions.

An addition brings what it needs. Add code.push and the role holds code.read too, because pushing code you cannot read makes no sense. A removal never takes anything else with it: if you remove a permission that something the role keeps needs, the role is refused and the message names the pair, so you decide what to do rather than finding out later.

Some permissions are never in a custom role. Deleting a group or repository, changing its visibility, and deciding who else administers access belong to Owner alone. A role cannot be based on Owner either.

A role counts as its base wherever a level is compared. A branch rule that lets Developers and above push lets in a role based on Developer — but only if the role still holds code.push. Removing a permission always wins.

Changing a role changes everyone who holds it. No grant moves, and yet every person, service account and team given the role gains or loses what you changed, everywhere it reaches. Preview the change first: the answer lists the permissions gained and lost, and how many grants and limits use the role. Every change lands in the audit log with the same.

A role in use cannot be deleted. Change or revoke its grants first — removing someone's access should be something you do to them on purpose, not a side effect of tidying the list.

How to

Define a role

Choose a slug — lowercase letters, digits and hyphens, unique in your organisation — a display name, a base, and the permissions to add and remove.

The web app has no screen for this yet; use the CLI or the API.

Terminalbash
gitmoap roles create-role \
--group-id <id> \
--base-role guest|reporter|developer|maintainer|owner \
--name <name> \
--slug <slug>
curlbash
curl -X POST https://api.gitmoap.example/groups/{group_id}/roles \
-H "Authorization: Bearer $GITMOAP_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "base_role": "<one of developer | guest | maintainer | owner | reporter>", "name": "<string>", "slug": "<string>" }'

See your organisation's roles

The web app has no screen for this yet; use the CLI or the API.

Terminalbash
gitmoap roles list-roles --group-id <id>
curlbash
curl -X GET https://api.gitmoap.example/groups/{group_id}/roles \
-H "Authorization: Bearer $GITMOAP_TOKEN"

The web app has no screen for this yet; use the CLI or the API.

Terminalbash
gitmoap roles get-role --role-id <id>
curlbash
curl -X GET https://api.gitmoap.example/roles/{role_id} \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Change a role, after seeing what it changes

Send only what changes. added and removed, when you send them, replace the lists they name. Add dry_run=true — --dry-run in the CLI — to see the permissions gained and lost and how many grants use the role, and change nothing.

The web app has no screen for this yet; use the CLI or the API.

Terminalbash
gitmoap roles update-role --role-id <id>
curlbash
curl -X PATCH https://api.gitmoap.example/roles/{role_id} \
-H "Authorization: Bearer $GITMOAP_TOKEN"

See where a role is used

Every grant of the role on a group or repository you can see, and how many limits cap someone at it. If it is also given somewhere you cannot see, hidden_scopes says so.

The web app has no screen for this yet; use the CLI or the API.

Terminalbash
gitmoap roles get-role-usage --role-id <id>
curlbash
curl -X GET https://api.gitmoap.example/roles/{role_id}/usage \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Delete a role

A role still given somewhere, or capping a limit, cannot be deleted: change or revoke those first, using the role's usage to find them.

Warning

Deleting a role cannot be undone. Defining one again with the same name makes a new role, which no grant or limit names until you give it again.

The web app has no screen for this yet; use the CLI or the API.

Terminalbash
gitmoap roles delete-role --role-id <id>
curlbash
curl -X DELETE https://api.gitmoap.example/roles/{role_id} \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Reference

6 endpoints

GET/groups/{group_id}/rolesrole:read

An organization's custom roles.

list_rolesGET /groups/{group_id}/rolesOpen in the API reference

Token scope

role:read

Send

Path
  • group_iduuidThe organization's top-level group
Query
  • limitint64optionalMaximum number of roles, 1-100 (default 50)
  • next_tokenstringoptionalPagination token

Refuses

  • 400Invalid pagination token, or the group is not an organization's top-level group
  • 401Authentication required
  • 403Only members of the organization see its roles
  • 404Group not found

Receive

  • next_tokenobjectoptional
  • roles[]object9 fields
    • base_roledeveloperguestmaintainerownerreporter
    • created_atdate-time
    • created_byobjectoptional
    • descriptionstring
    • namestring
    • organization_iduuid
    • role_iduuid
    • slugstring
    • updated_atdate-time
POST/groups/{group_id}/rolesrole:manage

Define a custom role.

create_rolePOST /groups/{group_id}/rolesOpen in the API reference

Token scope

role:manage

Counts against

custom_roles_per_org

Send

Path
  • group_iduuidThe organization's top-level group
Body
  • base_roledeveloperguestmaintainerownerreporter
  • descriptionobjectoptional
  • namestring
  • slugstring

Refuses

  • 400Invalid request, an unknown permission, or the group is not an organization's top-level group
  • 401Authentication required
  • 403Only the organization's owners define roles
  • 404Group not found
  • 409The organization already has a role with this slug
  • 422The role would be based on Owner, hold a permission only Owner may, or keep a permission without what it needs
  • 429Custom role limit reached for this organization

Receive

  • base_roledeveloperguestmaintainerownerreporter
  • created_atdate-time
  • created_byobjectoptional
  • descriptionstring
  • namestring
  • organization_iduuid
  • role_iduuid
  • slugstring
  • updated_atdate-time
GET/roles/{role_id}role:read

One custom role.

get_roleGET /roles/{role_id}Open in the API reference

Token scope

role:read

Send

Path
  • role_iduuidRole ID

Refuses

  • 400Invalid role id
  • 401Authentication required
  • 403The token lacks the scope
  • 404Role not found

Receive

The same shape create_role returns — 9 fields. Go to it

Show it here
  • base_roledeveloperguestmaintainerownerreporter
  • created_atdate-time
  • created_byobjectoptional
  • descriptionstring
  • namestring
  • organization_iduuid
  • role_iduuid
  • slugstring
  • updated_atdate-time
PATCH/roles/{role_id}role:manage

Change a custom role — and with it, everyone who holds it.

update_rolePATCH /roles/{role_id}Open in the API reference

Token scope

role:manage

Send

Path
  • role_iduuidRole ID
Query
  • dry_runbooleanoptionalSay what would change and for how many grants, and change nothing
Body
  • base_roleobjectoptional
  • descriptionobjectoptional
  • nameobjectoptional
  • slugobjectoptional

Refuses

  • 400Invalid request, or an unknown permission
  • 401Authentication required
  • 403Only the organization's owners change roles
  • 404Role not found
  • 409The organization already has a role with this slug
  • 422The role would be based on Owner, hold a permission only Owner may, or keep a permission without what it needs

Receive

  • dry_runboolean
  • grants_affectedint64Grants of this role, each of which changes with it — on every group and repository they reach.
  • limits_affectedint64Limits capping someone at this role.
  • roleobject9 fields
    • base_roledeveloperguestmaintainerownerreporter
    • created_atdate-time
    • created_byobjectoptional
    • descriptionstring
    • namestring
    • organization_iduuid
    • role_iduuid
    • slugstring
    • updated_atdate-time
DELETE/roles/{role_id}role:manage

Delete a custom role nothing uses.

delete_roleDELETE /roles/{role_id}Open in the API reference

Token scope

role:manage

Send

Path
  • role_iduuidRole ID

Refuses

  • 400Invalid role id
  • 401Authentication required
  • 403Only the organization's owners delete roles
  • 404Role not found
  • 409The role is still granted, or is a limit's ceiling

Receive

No body.

GET/roles/{role_id}/usagerole:read

Where a custom role is granted, as far as you can see.

get_role_usageGET /roles/{role_id}/usageOpen in the API reference

Token scope

role:read

Send

Path
  • role_iduuidRole ID
Query
  • limitint64optionalMaximum number of grants, 1-100 (default 50)
  • next_tokenstringoptionalPagination token

Refuses

  • 400Invalid pagination token
  • 401Authentication required
  • 403The token lacks the scope
  • 404Role not found

Receive

  • grants[]object7 fields
    • atobject3 fields
      • full_pathstring
      • idstring
      • typegrouprepository
    • created_atdate-time
    • expires_atdate-timeoptional
    • grant_iduuid
    • subjectobjectWho holds a grant.
  • hidden_scopesbooleanWhether the role is also granted somewhere you cannot see. Those places are never named.
  • limitsint64Limits capping someone at this role, across the organization.
  • next_tokenobjectoptional

Limits

Custom roles per organisation — 5 on the Free plan.

PlanCustom roles per organisation
Free5
Pro20
Team50
Enterprise50

At the limit, defining another is refused with 429 TOO_MANY_REQUESTS. Delete roles nobody uses, or raise the limit: a higher plan lifts it, and an Owner can ask for a higher limit on one namespace.

Troubleshooting

403 FORBIDDENdefining or changing a role
Cause
Only the organisation's Owners manage roles, or your token lacks role:manage
What to do
Ask an Owner, or mint a token that names role:manage
400 BAD_REQUESTnaming a permission
Cause
The key is not in the catalogue
What to do
Check the spelling against gitmoap access list-access-permissions
422 UNPROCESSABLE_ENTITY— RESERVED_PERMISSION
Cause
The role would hold something only Owner may
What to do
Leave it out; give Owner to the people who need it
422 UNPROCESSABLE_ENTITY— PERMISSION_DEPENDENCY
Cause
A removal leaves a permission without what it needs, or removes scope.view
What to do
Remove the dependent permission too, or keep what it needs
422 UNPROCESSABLE_ENTITY— ROLE_BASE_OWNER
Cause
Owner was chosen as the base
What to do
Base the role on Maintainer or below
409 CONFLICT— ROLE_SLUG_TAKEN
Cause
Your organisation already has a role with this slug
What to do
Choose another slug
409 CONFLICT— ROLE_IN_USE
Cause
The role is still given somewhere, caps a limit, or is what single sign-on gives newcomers — the connection's default role or a pending invite
What to do
Find the grants with the role's usage, change or revoke them, change the sign-on default and the invites, then delete
409 CONFLICT— USE_ACCESS_API changing someone on the members page
Cause
Their access here is a custom role
What to do
Change or revoke it through access

Examples

A release manager who cannot delete branches

shellscript
gitmoap roles create-role --group-id acme --slug release-manager --name "Release manager" \
--base-role developer --added '["policies.manage"]' --removed '["code.delete_branches"]'

Check what removing a permission would do before doing it

shellscript
gitmoap roles update-role --role-id <role-id> --removed '["merge_requests.merge"]' --dry-run \
--output json | jq '{lost: .permissions_removed, grants: .grants_affected}'

FAQ

Can a subgroup define its own roles?

No. Roles belong to the organisation, so one name means one thing everywhere in it.

What happens to my roles when the platform adds a permission?

A role gains a new permission if its base role gains it — the same as everyone holding that built-in role. It never gains a permission you removed.

Does a custom role appear on the members page?

No. The members page shows the built-in roles people hold directly; custom roles are listed, changed and revoked through Access.

  • Accessgiving a role on a group or repository, and seeing why someone can do something
  • Teamsgiving a role to a named set of people at once
  • Access tokensthe scopes a token needs to call these operations
  • Audit logevery change to a role, with what it added and removed