> For the complete documentation index, see [llms.txt](https://docs.material.security/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.material.security/reference/api-v1/roles.md).

# Roles

**Overview**

The Roles API lists the [roles](https://docs.material.security/learn-more/administration/admin-roles) you can assign to accounts and groups. Role definitions are built into Material and can't be created or changed. This catalog exists so you can discover the assignable role IDs on your instance without hardcoding them.

* [**List Roles**](https://docs.material.security/reference/api-v1/roles#get-api-v1-roles) (`GET /api/v1/roles`): the assignable roles on your instance, with each one's ID, display name, description, and scope

Role assignments are managed through the account and group update endpoints, using the `roles` field of [**Update Account**](https://docs.material.security/reference/api-v1/accounts#patch-api-v1-accounts-id) and [**Update Group**](https://docs.material.security/reference/api-v1/groups#patch-api-v1-groups-id). For what each role can do, see [Role Descriptions](https://docs.material.security/learn-more/administration/admin-roles/role-descriptions).

**Scope is part of the role ID**

Each ID names a role and the scope it applies at, mirroring the role list under **Edit Roles** (**Explorer** > **Accounts**). The `flavor` field reports which of the three it is:

* **Tenant-scoped** IDs (`flavor: "tenant"`), such as `analyst`, `tenant_admin`, and `content_admin`, **require** `tenants` when assigned.
* **Global** IDs (`flavor: "global"`), such as `super_admin` and `global_analyst`, apply to every tenant and **reject** `tenants`.
* **Individual** IDs (`flavor: "individual"`), currently just `tenant_enroller`, grant no tenant access and take no `tenants`.

So the ID alone tells you how to construct a valid assignment, with no catalog lookup needed. Instances that disable global roles omit the global IDs from this catalog entirely and reject them on assignment. This response contains no tenant IDs, which appear only in assignment payloads.

**Assigning and removing**

`roles` takes `assign` and `remove` blocks, and only the roles you name are touched. It isn't a full-set replacement, so a tenant-scoped token can't accidentally clear assignments it can't see. Assigning a tenant-scoped role the account or group already holds replaces its tenant list, removing a role it doesn't hold does nothing, and naming the same ID in both blocks returns a 400.

Removal applies at every scope the role is held, so to narrow a tenant-scoped role rather than drop it, re-assign it with a shorter `tenants` list instead of removing it.

Roles read back on the account and group resources carry a `source`: `direct` (assigned on that account), `group` (inherited from the group named in `groupId`, and changeable only on that group), or `tenant` (granted to everyone in the tenant). A role reported with `tenants: "all"` was granted across every tenant, which you can read here but can't assign through this API.

**Permissions**

Reading this catalog needs the same read permission as accounts and groups. Changing assignments additionally requires role-management permission, and you can only grant roles you're allowed to bind yourself: a tenant administrator can't grant Super Admin, or grant anything outside their own tenants.

Be careful here. Nothing stops you from removing your own access or the last Super Admin, and either is irreversible without Material support.

**Response Structure**

The catalog follows the standard two-part structure: a `meta` object (with `totalCount`, `limit`, `hasMore`, and `nextCursor`) and an `items` array of role objects. The catalog is small and fixed, so this endpoint takes pagination only and no filters.

**Want a walkthrough?**

Review [Hello World](https://docs.material.security/reference/api-v1/hello-world).

**Pagination and Rate Limiting**

* Material APIs use **cursor-based pagination**: pass the `nextCursor` value from one response as the `cursor` parameter in the next request.
* The `limit` parameter controls page size and is locked into the cursor, so later pages keep the page size of the first request.
* When `hasMore` is false and `nextCursor` is null, you've reached the last page.

## List Roles

> Lists the roles that can be assigned to accounts and groups on this instance. Role definitions are built in, so only assignments are managed through the API, using the \`roles\` field of the account and group update endpoints. A role ID carries its scope: tenant-scoped IDs require \`tenants\` when assigned, while IDs that apply everywhere take none. Instances that disable global roles omit the global IDs entirely. The response contains no tenant IDs.

```json
{"openapi":"3.1.0","info":{"title":"Material Security API","version":"v1"},"tags":[{"name":"Roles","description":"**Overview**\n\nThe Roles API lists the [roles](https://docs.material.security/learn-more/administration/admin-roles) you can assign to accounts and groups. Role definitions are built into Material and can't be created or changed. This catalog exists so you can discover the assignable role IDs on your instance without hardcoding them.\n\n* **[List Roles](https://docs.material.security/reference/api-v1/roles#get-api-v1-roles)** (`GET /api/v1/roles`): the assignable roles on your instance, with each one's ID, display name, description, and scope\n\nRole assignments are managed through the account and group update endpoints, using the `roles` field of **[Update Account](https://docs.material.security/reference/api-v1/accounts#patch-api-v1-accounts-id)** and **[Update Group](https://docs.material.security/reference/api-v1/groups#patch-api-v1-groups-id)**. For what each role can do, see [Role Descriptions](https://docs.material.security/learn-more/administration/admin-roles/role-descriptions).\n\n**Scope is part of the role ID**\n\nEach ID names a role and the scope it applies at, mirroring the role list under **Edit Roles** (**Explorer** > **Accounts**). The `flavor` field reports which of the three it is:\n\n* **Tenant-scoped** IDs (`flavor: \"tenant\"`), such as `analyst`, `tenant_admin`, and `content_admin`, **require** `tenants` when assigned.\n* **Global** IDs (`flavor: \"global\"`), such as `super_admin` and `global_analyst`, apply to every tenant and **reject** `tenants`.\n* **Individual** IDs (`flavor: \"individual\"`), currently just `tenant_enroller`, grant no tenant access and take no `tenants`.\n\nSo the ID alone tells you how to construct a valid assignment, with no catalog lookup needed. Instances that disable global roles omit the global IDs from this catalog entirely and reject them on assignment. This response contains no tenant IDs, which appear only in assignment payloads.\n\n**Assigning and removing**\n\n`roles` takes `assign` and `remove` blocks, and only the roles you name are touched. It isn't a full-set replacement, so a tenant-scoped token can't accidentally clear assignments it can't see. Assigning a tenant-scoped role the account or group already holds replaces its tenant list, removing a role it doesn't hold does nothing, and naming the same ID in both blocks returns a 400.\n\nRemoval applies at every scope the role is held, so to narrow a tenant-scoped role rather than drop it, re-assign it with a shorter `tenants` list instead of removing it.\n\nRoles read back on the account and group resources carry a `source`: `direct` (assigned on that account), `group` (inherited from the group named in `groupId`, and changeable only on that group), or `tenant` (granted to everyone in the tenant). A role reported with `tenants: \"all\"` was granted across every tenant, which you can read here but can't assign through this API.\n\n**Permissions**\n\nReading this catalog needs the same read permission as accounts and groups. Changing assignments additionally requires role-management permission, and you can only grant roles you're allowed to bind yourself: a tenant administrator can't grant Super Admin, or grant anything outside their own tenants.\n\nBe careful here. Nothing stops you from removing your own access or the last Super Admin, and either is irreversible without Material support.\n\n**Response Structure**\n\nThe catalog follows the standard two-part structure: a `meta` object (with `totalCount`, `limit`, `hasMore`, and `nextCursor`) and an `items` array of role objects. The catalog is small and fixed, so this endpoint takes pagination only and no filters.\n\n**Want a walkthrough?**\n\nReview [Hello World](https://docs.material.security/reference/api-v1/hello-world).\n\n**Pagination and Rate Limiting**\n\n* Material APIs use **cursor-based pagination**: pass the `nextCursor` value from one response as the `cursor` parameter in the next request.\n* The `limit` parameter controls page size and is locked into the cursor, so later pages keep the page size of the first request.\n* When `hasMore` is false and `nextCursor` is null, you've reached the last page.\n"}],"servers":[{"url":"https://{domain}","description":"Material Security instance","variables":{"domain":{"default":"your-instance.on.material.security","description":"Your Material Security instance domain"}}}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-material-client-secret","description":"Material Security API key"}},"schemas":{"APIRoleCollection":{"title":"APIRoleCollection","type":"object","properties":{"meta":{"$ref":"#/components/schemas/CollectionMeta"},"items":{"type":"array","items":{"$ref":"#/components/schemas/APIRole"}}},"required":["meta","items"]},"CollectionMeta":{"title":"CollectionMeta","type":"object","properties":{"totalCount":{"description":"The total number of items matching the query.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"description":"The page size used for this response.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"hasMore":{"description":"True if more items exist beyond the current page; false otherwise.","type":"boolean"},"nextCursor":{"description":"The cursor to fetch the next page of results. Pass this value to the `cursor` query parameter. Null if no more pages exist.","anyOf":[{"type":"string"},{"type":"null"}]}}},"APIRole":{"title":"APIRole","description":"An assignable [role](https://docs.material.security/learn-more/administration/admin-roles). Role definitions are built in, so only assignments are managed through the API.","type":"object","properties":{"id":{"description":"Role ID. The ID carries the role's scope: tenant-scoped IDs (for example `analyst`) require `tenants`, while IDs that apply everywhere (for example `global_analyst`, `super_admin`, `tenant_enroller`) take none. Call `GET /roles` for the IDs available on your instance.","type":"string","enum":["super_admin","global_analyst","global_issue_responder","global_phishing_simulation_admin","global_analytics_admin","global_settings_admin","tenant_admin","content_admin","drive_content_admin","email_content_admin","analyst","issue_responder","ediscovery_admin","phishing_simulation_admin","analytics_admin","settings_admin","tenant_enroller"]},"name":{"description":"Display name, as shown under **Edit Roles**.","type":"string"},"description":{"description":"What the role allows, as shown under **Edit Roles**. See [Role Descriptions](https://docs.material.security/learn-more/administration/admin-roles/role-descriptions) for the full breakdown.","type":"string"},"flavor":{"description":"Scope of the ID: `tenant` requires `tenants` when you assign it, `global` applies to every tenant and takes no `tenants`, and `individual` grants no tenant access at all.","type":"string","enum":["global","tenant","individual"]}},"required":["id","name","description","flavor"]},"ValidationErrorResponse":{"title":"Validation Error Response","type":"object","properties":{"error":{"description":"A human-readable description of the error.","type":"string"},"validationFailures":{"description":"List of individual validation failures when request parameters fail schema validation.","type":"array","items":{"type":"object","properties":{},"additionalProperties":{}}}},"required":["error"]},"ErrorResponse":{"title":"Error Response","type":"object","properties":{"error":{"description":"A human-readable description of the error.","type":"string"}},"required":["error"]}}},"paths":{"/api/v1/roles":{"get":{"operationId":"listRoles","summary":"List Roles","description":"Lists the roles that can be assigned to accounts and groups on this instance. Role definitions are built in, so only assignments are managed through the API, using the `roles` field of the account and group update endpoints. A role ID carries its scope: tenant-scoped IDs require `tenants` when assigned, while IDs that apply everywhere take none. Instances that disable global roles omit the global IDs entirely. The response contains no tenant IDs.","tags":["Roles"],"parameters":[{"in":"query","name":"cursor","schema":{"description":"The pagination cursor returned in a previous response. Pass this value to retrieve the next page of results.","type":"string"},"description":"The pagination cursor returned in a previous response. Pass this value to retrieve the next page of results."},{"in":"query","name":"limit","schema":{"description":"The maximum number of items to return per page.","type":"integer"},"description":"The maximum number of items to return per page."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/APIRoleCollection"}}}},"400":{"description":"Bad request: invalid parameters or request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized: missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden: the API key doesn't have permission to perform this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found: the requested resource doesn't exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests: the client has exceeded a rate limit and should retry later","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.material.security/reference/api-v1/roles.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
