> 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/groups.md).

# Groups

**Overview**

The Groups API provides programmatic access to the directory groups synced from your Google, Microsoft, or Okta tenant: Google groups, Google org units, Microsoft groups, and Okta groups. List and filter groups, retrieve one by its encoded ID, list a group's member accounts, and update its licenses, per-group setting overrides, and the roles it grants. Each group exposes its type, name, email, member count, licenses, and effective settings with the [layer they resolve from](https://docs.material.security/learn-more/administration/settings-hierarchy).

Five endpoints make up the Groups API:

* [**List Groups**](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups) (`GET /api/v1/groups`): filter, sort, and page through groups
* [**Get Group**](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups-id) (`GET /api/v1/groups/{id}`): retrieve a single group by its encoded ID
* [**List Group Members**](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups-id-members) (`GET /api/v1/groups/{id}/members`): retrieve the accounts that belong to a group
* [**Update Group**](https://docs.material.security/reference/api-v1/groups#patch-api-v1-groups-id) (`PATCH /api/v1/groups/{id}`): update a group's licenses and setting overrides
* [**Bulk Groups**](https://docs.material.security/reference/api-v1/groups#post-api-v1-groups-bulk) (`POST /api/v1/groups/bulk`): apply up to 200 group update operations in one request

**Filtering**

List accepts `search` (a loose match on name, description, email, or org-unit path), `email`, `type` (`okta`, `google_group`, `google_org_unit`, or `microsoft_group`), `memberOf` (encoded account IDs), `role`, and `hasOverrides`. Per-setting filters use dotted params, for example `setting.emailThreatRemediation=on`, and take `on`, `off`, or `overridden`. These match the group's own override rather than the value it inherits. Comma-separated values match any of the listed values within a single filter, and each filter you add narrows the result set further.

**Sorting**

Sort with `?sort=<field>:asc|desc`. Supported fields: `name` (default) and `memberCount`.

**Read-only fields**

Name, email, aliases, and membership are synced from your provider and can't be changed through this API. What you can write is `licenses`, `settings`, and `roles`. Setting a value to `default` clears the [group-level override](https://docs.material.security/learn-more/administration/group-and-account-customization) so the group inherits again.

Changing `roles` additionally requires role-management permission. A [role](https://docs.material.security/learn-more/administration/admin-roles) granted here applies to every member of the group, and nothing stops you from removing the last Super Admin, which is irreversible without Material support.

**Response Structure**

List responses follow the standard two-part structure: a `meta` object (with `totalCount`, `limit`, `hasMore`, and `nextCursor`) and an `items` array.

A group's `settings` is an array, not a single object. A group can span several tenants, and its own override is instance-wide, but what that override inherits differs per tenant, so the response carries one entry per tenant you can access, each with its own `settings` and `licenses` and the layer they resolve from. To read what the group itself overrides, which is what `PATCH` writes and what the `setting.<name>` and `hasOverrides` filters match, take the entries of any tenant whose `source` is `group`.

**Bulk** responses return `results`, one entry per operation in request order, so `results[i]` corresponds to `operations[i]`, plus a `meta` object counting how many succeeded and failed. Operations are applied best-effort: a well-formed envelope always returns 200, and individual failures are reported in `results[]`.

**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 Groups

> Retrieves a paginated list of directory groups (Google groups, Google org units, Microsoft groups, Okta groups) synced from a provider. Filter by type, member account, per-setting overrides, and effective settings, and sort by name or member count.

```json
{"openapi":"3.1.0","info":{"title":"Material Security API","version":"v1"},"tags":[{"name":"Groups","description":"**Overview**\n\nThe Groups API provides programmatic access to the directory groups synced from your Google, Microsoft, or Okta tenant: Google groups, Google org units, Microsoft groups, and Okta groups. List and filter groups, retrieve one by its encoded ID, list a group's member accounts, and update its licenses, per-group setting overrides, and the roles it grants. Each group exposes its type, name, email, member count, licenses, and effective settings with the [layer they resolve from](https://docs.material.security/learn-more/administration/settings-hierarchy).\n\nFive endpoints make up the Groups API:\n\n* **[List Groups](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups)** (`GET /api/v1/groups`): filter, sort, and page through groups\n* **[Get Group](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups-id)** (`GET /api/v1/groups/{id}`): retrieve a single group by its encoded ID\n* **[List Group Members](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups-id-members)** (`GET /api/v1/groups/{id}/members`): retrieve the accounts that belong to a group\n* **[Update Group](https://docs.material.security/reference/api-v1/groups#patch-api-v1-groups-id)** (`PATCH /api/v1/groups/{id}`): update a group's licenses and setting overrides\n* **[Bulk Groups](https://docs.material.security/reference/api-v1/groups#post-api-v1-groups-bulk)** (`POST /api/v1/groups/bulk`): apply up to 200 group update operations in one request\n\n**Filtering**\n\nList accepts `search` (a loose match on name, description, email, or org-unit path), `email`, `type` (`okta`, `google_group`, `google_org_unit`, or `microsoft_group`), `memberOf` (encoded account IDs), `role`, and `hasOverrides`. Per-setting filters use dotted params, for example `setting.emailThreatRemediation=on`, and take `on`, `off`, or `overridden`. These match the group's own override rather than the value it inherits. Comma-separated values match any of the listed values within a single filter, and each filter you add narrows the result set further.\n\n**Sorting**\n\nSort with `?sort=<field>:asc|desc`. Supported fields: `name` (default) and `memberCount`.\n\n**Read-only fields**\n\nName, email, aliases, and membership are synced from your provider and can't be changed through this API. What you can write is `licenses`, `settings`, and `roles`. Setting a value to `default` clears the [group-level override](https://docs.material.security/learn-more/administration/group-and-account-customization) so the group inherits again.\n\nChanging `roles` additionally requires role-management permission. A [role](https://docs.material.security/learn-more/administration/admin-roles) granted here applies to every member of the group, and nothing stops you from removing the last Super Admin, which is irreversible without Material support.\n\n**Response Structure**\n\nList responses follow the standard two-part structure: a `meta` object (with `totalCount`, `limit`, `hasMore`, and `nextCursor`) and an `items` array.\n\nA group's `settings` is an array, not a single object. A group can span several tenants, and its own override is instance-wide, but what that override inherits differs per tenant, so the response carries one entry per tenant you can access, each with its own `settings` and `licenses` and the layer they resolve from. To read what the group itself overrides, which is what `PATCH` writes and what the `setting.<name>` and `hasOverrides` filters match, take the entries of any tenant whose `source` is `group`.\n\n**Bulk** responses return `results`, one entry per operation in request order, so `results[i]` corresponds to `operations[i]`, plus a `meta` object counting how many succeeded and failed. Operations are applied best-effort: a well-formed envelope always returns 200, and individual failures are reported in `results[]`.\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":{"APIGroupCollection":{"title":"APIGroupCollection","type":"object","properties":{"meta":{"$ref":"#/components/schemas/CollectionMeta"},"items":{"type":"array","items":{"$ref":"#/components/schemas/APIGroup"}}},"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"}]}}},"APIGroup":{"title":"APIGroup","description":"A directory group (Google group, Google org unit, Microsoft group, or Okta group) synced from your provider. A group can span several tenants and its own override is instance-wide, so `settings` reports how that override resolves inside each tenant your token can access.","type":"object","properties":{"id":{"description":"The encoded group ID. Format: `grp.1.<base64>`.","type":"string"},"type":{"description":"The kind of directory group: `okta` (Okta), `google_group` (Google Group), `google_org_unit` (Google Org Unit), or `microsoft_group` (Microsoft Group).","type":"string","enum":["okta","google_group","google_org_unit","microsoft_group"]},"name":{"description":"The group's display name.","type":"string"},"description":{"description":"The group's description. An empty string if it has none.","type":"string"},"email":{"description":"The group's primary email address. Null for Okta groups and Google org units, which have none.","anyOf":[{"type":"string"},{"type":"null"}]},"aliases":{"description":"Additional email addresses that reach this group.","type":"array","items":{"type":"string"}},"memberCount":{"description":"Estimated number of accounts in the group.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"roles":{"description":"The [roles](https://docs.material.security/learn-more/administration/admin-roles) this group grants to every one of its members. Empty if the group grants none. Members see these on their own account with `source: \"group\"`.","type":"array","items":{"$ref":"#/components/schemas/APIGroupAssignedRole"}},"settings":{"description":"Settings and licenses resolved per tenant, with one entry per tenant your token can access, ordered by tenant ID. Empty when your token can access none of them. To read what the group itself overrides, which is what `PATCH` writes and what the `setting.<name>` and `hasOverrides` filters match, take the entries of any tenant whose `source` is `group`.","type":"array","items":{"$ref":"#/components/schemas/APIGroupTenantSettings"}},"lastUpdatedAt":{"description":"When Material last synced this group, in ISO 8601 format. Null if it has never synced.","anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["id","type","name","description","email","aliases","memberCount","roles","settings","lastUpdatedAt"]},"APIGroupAssignedRole":{"title":"APIGroupAssignedRole","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"]},"tenants":{"description":"Tenants the role applies to, as encoded tenant IDs (format `tnt.1.<base64>`), for tenant-scoped IDs only. `\"all\"` means the role was granted across every tenant, which you can read but not assign through this API.","anyOf":[{"type":"array","items":{"type":"string"}},{"type":"string","const":"all"}]}},"required":["id"]},"APIGroupTenantSettings":{"title":"APIGroupTenantSettings","type":"object","properties":{"tenant":{"description":"The tenant these values are resolved in, as an encoded tenant ID (format `tnt.1.<base64>`).","type":"string"},"settings":{"$ref":"#/components/schemas/APIGroupSettings"},"licenses":{"$ref":"#/components/schemas/APIGroupLicenses"}},"required":["tenant","settings","licenses"]},"APIGroupSettings":{"title":"APIGroupSettings","description":"Each product setting's effective value for this group in one tenant, with the layer it resolves from. See [Group and Account Customization](https://docs.material.security/learn-more/administration/group-and-account-customization) for how overrides work.","type":"object","properties":{"emailSync":{"title":"APIGroupBooleanSetting","description":"Whether Material syncs members' mailboxes. Shown as **Mailbox Syncing** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"fileSync":{"title":"APIGroupBooleanSetting","description":"Whether Material syncs members' Google Drive files. Shown as **My Drive Syncing** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"emailThreatRemediation":{"title":"APIGroupBooleanSetting","description":"Whether Material remediates email threats found in members' mailboxes. Shown as **Email Threat Remediation** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"fileRemediation":{"title":"APIGroupBooleanSetting","description":"Whether Material remediates risky sharing on members' files. Shown as **File Remediation** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"sensitiveEmailRedaction":{"title":"APIGroupBooleanSetting","description":"Whether Material redacts sensitive email in members' mailboxes. Shown as **Sensitive Email Redaction** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"passwordResetProtection":{"title":"APIGroupBooleanSetting","description":"Whether Material holds password reset and app signup email for members during a lockdown. Shown as **Password Reset & App Signup Protection** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"oauthAppRemediation":{"title":"APIGroupBooleanSetting","description":"Whether Material revokes members' grants when an OAuth app carries a revoke policy. Shown as **OAuth App Remediation** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"emailBombProtection":{"title":"APIGroupModeSetting","description":"How Material handles a sudden surge of email to a member. Shown as **[Email Bomb Protection](https://docs.material.security/learn-more/risk-areas/email-threats/detect/material-email-threat-detections/email-bomb-protection)** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupModeSetting"}},"required":["emailSync","fileSync","emailThreatRemediation","fileRemediation","sensitiveEmailRedaction","passwordResetProtection","oauthAppRemediation","emailBombProtection"]},"APIGroupBooleanSetting":{"title":"APIGroupBooleanSetting","type":"object","properties":{"enabled":{"description":"Whether the setting is enabled for this group in this tenant.","type":"boolean"},"source":{"description":"Which layer the effective value comes from: `group`, `tenant`, or `default`. Groups have no account layer. See [Settings Hierarchy](https://docs.material.security/learn-more/administration/settings-hierarchy) for how the layers resolve.","type":"string","enum":["group","tenant","default"]}},"required":["enabled","source"]},"APIGroupModeSetting":{"title":"APIGroupModeSetting","type":"object","properties":{"mode":{"description":"How [Email Bomb Protection](https://docs.material.security/learn-more/risk-areas/email-threats/detect/material-email-threat-detections/email-bomb-protection) is applied to this group's members in this tenant: `enabled` (detect and remediate), `detection_only` (detect without remediating), or `disabled`.","type":"string","enum":["enabled","detection_only","disabled"]},"source":{"description":"Which layer the effective value comes from: `group`, `tenant`, or `default`. Groups have no account layer. See [Settings Hierarchy](https://docs.material.security/learn-more/administration/settings-hierarchy) for how the layers resolve.","type":"string","enum":["group","tenant","default"]}},"required":["mode","source"]},"APIGroupLicenses":{"title":"APIGroupLicenses","type":"object","properties":{"values":{"description":"The licenses this group allocates to its members: `essentials` (Essentials), `advanced` (Advanced), or `ato_resilience` (ATO Resilience). A group allocates at most one tier, `essentials` or `advanced`, and can add `ato_resilience` alongside it.","type":"array","items":{"type":"string","enum":["essentials","advanced","ato_resilience"]}},"source":{"description":"Which layer the effective value comes from: `group`, `tenant`, or `default`. Groups have no account layer. See [Settings Hierarchy](https://docs.material.security/learn-more/administration/settings-hierarchy) for how the layers resolve.","type":"string","enum":["group","tenant","default"]}},"required":["values","source"]},"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/groups":{"get":{"operationId":"listGroups","summary":"List Groups","description":"Retrieves a paginated list of directory groups (Google groups, Google org units, Microsoft groups, Okta groups) synced from a provider. Filter by type, member account, per-setting overrides, and effective settings, and sort by name or member count.","tags":["Groups"],"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."},{"in":"query","name":"search","schema":{"description":"Loose match on the group's name, description, email address, or org-unit path.","type":"string"},"description":"Loose match on the group's name, description, email address, or org-unit path."},{"in":"query","name":"email","schema":{"description":"Filter to these exact email addresses, comma-separated.","type":"string"},"description":"Filter to these exact email addresses, comma-separated."},{"in":"query","name":"type","schema":{"description":"Filter by the kind of directory group: `okta` (Okta), `google_group` (Google Group), `google_org_unit` (Google Org Unit), or `microsoft_group` (Microsoft Group).","type":"string","enum":["okta","google_group","google_org_unit","microsoft_group"]},"description":"Filter by the kind of directory group: `okta` (Okta), `google_group` (Google Group), `google_org_unit` (Google Org Unit), or `microsoft_group` (Microsoft Group)."},{"in":"query","name":"memberOf","schema":{"description":"Filter to the groups that any of these accounts belong to, as comma-separated encoded account IDs (format `acct.1.<base64>`).","type":"string"},"description":"Filter to the groups that any of these accounts belong to, as comma-separated encoded account IDs (format `acct.1.<base64>`)."},{"in":"query","name":"hasOverrides","schema":{"description":"Filter to groups that define at least one setting override of their own (true) or none at all (false).","type":"boolean"},"description":"Filter to groups that define at least one setting override of their own (true) or none at all (false)."},{"in":"query","name":"role","schema":{"description":"Filter to groups that grant any of these roles to their members, comma-separated. Call `GET /roles` for the IDs available on your instance.","type":"string"},"description":"Filter to groups that grant any of these roles to their members, comma-separated. Call `GET /roles` for the IDs available on your instance."},{"in":"query","name":"setting.emailSync","schema":{"description":"Filter by the group's own `emailSync` override: `on` or `off` (the group's override sets that value), or `overridden` (the group defines an override, whatever the value). Matches the group's own override, not the value it inherits.","type":"string","enum":["on","off","overridden"]},"description":"Filter by the group's own `emailSync` override: `on` or `off` (the group's override sets that value), or `overridden` (the group defines an override, whatever the value). Matches the group's own override, not the value it inherits."},{"in":"query","name":"setting.fileSync","schema":{"description":"Filter by the group's own `fileSync` override: `on` or `off` (the group's override sets that value), or `overridden` (the group defines an override, whatever the value). Matches the group's own override, not the value it inherits.","type":"string","enum":["on","off","overridden"]},"description":"Filter by the group's own `fileSync` override: `on` or `off` (the group's override sets that value), or `overridden` (the group defines an override, whatever the value). Matches the group's own override, not the value it inherits."},{"in":"query","name":"setting.emailThreatRemediation","schema":{"description":"Filter by the group's own `emailThreatRemediation` override: `on` or `off` (the group's override sets that value), or `overridden` (the group defines an override, whatever the value). Matches the group's own override, not the value it inherits.","type":"string","enum":["on","off","overridden"]},"description":"Filter by the group's own `emailThreatRemediation` override: `on` or `off` (the group's override sets that value), or `overridden` (the group defines an override, whatever the value). Matches the group's own override, not the value it inherits."},{"in":"query","name":"setting.fileRemediation","schema":{"description":"Filter by the group's own `fileRemediation` override: `on` or `off` (the group's override sets that value), or `overridden` (the group defines an override, whatever the value). Matches the group's own override, not the value it inherits.","type":"string","enum":["on","off","overridden"]},"description":"Filter by the group's own `fileRemediation` override: `on` or `off` (the group's override sets that value), or `overridden` (the group defines an override, whatever the value). Matches the group's own override, not the value it inherits."},{"in":"query","name":"setting.sensitiveEmailRedaction","schema":{"description":"Filter by the group's own `sensitiveEmailRedaction` override: `on` or `off` (the group's override sets that value), or `overridden` (the group defines an override, whatever the value). Matches the group's own override, not the value it inherits.","type":"string","enum":["on","off","overridden"]},"description":"Filter by the group's own `sensitiveEmailRedaction` override: `on` or `off` (the group's override sets that value), or `overridden` (the group defines an override, whatever the value). Matches the group's own override, not the value it inherits."},{"in":"query","name":"setting.passwordResetProtection","schema":{"description":"Filter by the group's own `passwordResetProtection` override: `on` or `off` (the group's override sets that value), or `overridden` (the group defines an override, whatever the value). Matches the group's own override, not the value it inherits.","type":"string","enum":["on","off","overridden"]},"description":"Filter by the group's own `passwordResetProtection` override: `on` or `off` (the group's override sets that value), or `overridden` (the group defines an override, whatever the value). Matches the group's own override, not the value it inherits."},{"in":"query","name":"setting.oauthAppRemediation","schema":{"description":"Filter by the group's own `oauthAppRemediation` override: `on` or `off` (the group's override sets that value), or `overridden` (the group defines an override, whatever the value). Matches the group's own override, not the value it inherits.","type":"string","enum":["on","off","overridden"]},"description":"Filter by the group's own `oauthAppRemediation` override: `on` or `off` (the group's override sets that value), or `overridden` (the group defines an override, whatever the value). Matches the group's own override, not the value it inherits."},{"in":"query","name":"setting.emailBombProtection","schema":{"description":"Filter by the group's own `emailBombProtection` override: `on` or `off` (the group's override sets that value), or `overridden` (the group defines an override, whatever the value). Matches the group's own override, not the value it inherits.","type":"string","enum":["on","off","overridden"]},"description":"Filter by the group's own `emailBombProtection` override: `on` or `off` (the group's override sets that value), or `overridden` (the group defines an override, whatever the value). Matches the group's own override, not the value it inherits."},{"in":"query","name":"sort","schema":{"description":"Sort field, e.g. `name:asc` or `memberCount:desc`. A single field only.","type":"string"},"description":"Sort field, e.g. `name:asc` or `memberCount:desc`. A single field only."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/APIGroupCollection"}}}},"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"}}}}}}}}}
```

## Get Group

> Retrieves the full details of a single group by its encoded ID, including type, name, email, member count, licenses, and effective settings with their source.

```json
{"openapi":"3.1.0","info":{"title":"Material Security API","version":"v1"},"tags":[{"name":"Groups","description":"**Overview**\n\nThe Groups API provides programmatic access to the directory groups synced from your Google, Microsoft, or Okta tenant: Google groups, Google org units, Microsoft groups, and Okta groups. List and filter groups, retrieve one by its encoded ID, list a group's member accounts, and update its licenses, per-group setting overrides, and the roles it grants. Each group exposes its type, name, email, member count, licenses, and effective settings with the [layer they resolve from](https://docs.material.security/learn-more/administration/settings-hierarchy).\n\nFive endpoints make up the Groups API:\n\n* **[List Groups](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups)** (`GET /api/v1/groups`): filter, sort, and page through groups\n* **[Get Group](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups-id)** (`GET /api/v1/groups/{id}`): retrieve a single group by its encoded ID\n* **[List Group Members](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups-id-members)** (`GET /api/v1/groups/{id}/members`): retrieve the accounts that belong to a group\n* **[Update Group](https://docs.material.security/reference/api-v1/groups#patch-api-v1-groups-id)** (`PATCH /api/v1/groups/{id}`): update a group's licenses and setting overrides\n* **[Bulk Groups](https://docs.material.security/reference/api-v1/groups#post-api-v1-groups-bulk)** (`POST /api/v1/groups/bulk`): apply up to 200 group update operations in one request\n\n**Filtering**\n\nList accepts `search` (a loose match on name, description, email, or org-unit path), `email`, `type` (`okta`, `google_group`, `google_org_unit`, or `microsoft_group`), `memberOf` (encoded account IDs), `role`, and `hasOverrides`. Per-setting filters use dotted params, for example `setting.emailThreatRemediation=on`, and take `on`, `off`, or `overridden`. These match the group's own override rather than the value it inherits. Comma-separated values match any of the listed values within a single filter, and each filter you add narrows the result set further.\n\n**Sorting**\n\nSort with `?sort=<field>:asc|desc`. Supported fields: `name` (default) and `memberCount`.\n\n**Read-only fields**\n\nName, email, aliases, and membership are synced from your provider and can't be changed through this API. What you can write is `licenses`, `settings`, and `roles`. Setting a value to `default` clears the [group-level override](https://docs.material.security/learn-more/administration/group-and-account-customization) so the group inherits again.\n\nChanging `roles` additionally requires role-management permission. A [role](https://docs.material.security/learn-more/administration/admin-roles) granted here applies to every member of the group, and nothing stops you from removing the last Super Admin, which is irreversible without Material support.\n\n**Response Structure**\n\nList responses follow the standard two-part structure: a `meta` object (with `totalCount`, `limit`, `hasMore`, and `nextCursor`) and an `items` array.\n\nA group's `settings` is an array, not a single object. A group can span several tenants, and its own override is instance-wide, but what that override inherits differs per tenant, so the response carries one entry per tenant you can access, each with its own `settings` and `licenses` and the layer they resolve from. To read what the group itself overrides, which is what `PATCH` writes and what the `setting.<name>` and `hasOverrides` filters match, take the entries of any tenant whose `source` is `group`.\n\n**Bulk** responses return `results`, one entry per operation in request order, so `results[i]` corresponds to `operations[i]`, plus a `meta` object counting how many succeeded and failed. Operations are applied best-effort: a well-formed envelope always returns 200, and individual failures are reported in `results[]`.\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":{"APIGroup":{"title":"APIGroup","description":"A directory group (Google group, Google org unit, Microsoft group, or Okta group) synced from your provider. A group can span several tenants and its own override is instance-wide, so `settings` reports how that override resolves inside each tenant your token can access.","type":"object","properties":{"id":{"description":"The encoded group ID. Format: `grp.1.<base64>`.","type":"string"},"type":{"description":"The kind of directory group: `okta` (Okta), `google_group` (Google Group), `google_org_unit` (Google Org Unit), or `microsoft_group` (Microsoft Group).","type":"string","enum":["okta","google_group","google_org_unit","microsoft_group"]},"name":{"description":"The group's display name.","type":"string"},"description":{"description":"The group's description. An empty string if it has none.","type":"string"},"email":{"description":"The group's primary email address. Null for Okta groups and Google org units, which have none.","anyOf":[{"type":"string"},{"type":"null"}]},"aliases":{"description":"Additional email addresses that reach this group.","type":"array","items":{"type":"string"}},"memberCount":{"description":"Estimated number of accounts in the group.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"roles":{"description":"The [roles](https://docs.material.security/learn-more/administration/admin-roles) this group grants to every one of its members. Empty if the group grants none. Members see these on their own account with `source: \"group\"`.","type":"array","items":{"$ref":"#/components/schemas/APIGroupAssignedRole"}},"settings":{"description":"Settings and licenses resolved per tenant, with one entry per tenant your token can access, ordered by tenant ID. Empty when your token can access none of them. To read what the group itself overrides, which is what `PATCH` writes and what the `setting.<name>` and `hasOverrides` filters match, take the entries of any tenant whose `source` is `group`.","type":"array","items":{"$ref":"#/components/schemas/APIGroupTenantSettings"}},"lastUpdatedAt":{"description":"When Material last synced this group, in ISO 8601 format. Null if it has never synced.","anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["id","type","name","description","email","aliases","memberCount","roles","settings","lastUpdatedAt"]},"APIGroupAssignedRole":{"title":"APIGroupAssignedRole","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"]},"tenants":{"description":"Tenants the role applies to, as encoded tenant IDs (format `tnt.1.<base64>`), for tenant-scoped IDs only. `\"all\"` means the role was granted across every tenant, which you can read but not assign through this API.","anyOf":[{"type":"array","items":{"type":"string"}},{"type":"string","const":"all"}]}},"required":["id"]},"APIGroupTenantSettings":{"title":"APIGroupTenantSettings","type":"object","properties":{"tenant":{"description":"The tenant these values are resolved in, as an encoded tenant ID (format `tnt.1.<base64>`).","type":"string"},"settings":{"$ref":"#/components/schemas/APIGroupSettings"},"licenses":{"$ref":"#/components/schemas/APIGroupLicenses"}},"required":["tenant","settings","licenses"]},"APIGroupSettings":{"title":"APIGroupSettings","description":"Each product setting's effective value for this group in one tenant, with the layer it resolves from. See [Group and Account Customization](https://docs.material.security/learn-more/administration/group-and-account-customization) for how overrides work.","type":"object","properties":{"emailSync":{"title":"APIGroupBooleanSetting","description":"Whether Material syncs members' mailboxes. Shown as **Mailbox Syncing** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"fileSync":{"title":"APIGroupBooleanSetting","description":"Whether Material syncs members' Google Drive files. Shown as **My Drive Syncing** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"emailThreatRemediation":{"title":"APIGroupBooleanSetting","description":"Whether Material remediates email threats found in members' mailboxes. Shown as **Email Threat Remediation** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"fileRemediation":{"title":"APIGroupBooleanSetting","description":"Whether Material remediates risky sharing on members' files. Shown as **File Remediation** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"sensitiveEmailRedaction":{"title":"APIGroupBooleanSetting","description":"Whether Material redacts sensitive email in members' mailboxes. Shown as **Sensitive Email Redaction** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"passwordResetProtection":{"title":"APIGroupBooleanSetting","description":"Whether Material holds password reset and app signup email for members during a lockdown. Shown as **Password Reset & App Signup Protection** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"oauthAppRemediation":{"title":"APIGroupBooleanSetting","description":"Whether Material revokes members' grants when an OAuth app carries a revoke policy. Shown as **OAuth App Remediation** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"emailBombProtection":{"title":"APIGroupModeSetting","description":"How Material handles a sudden surge of email to a member. Shown as **[Email Bomb Protection](https://docs.material.security/learn-more/risk-areas/email-threats/detect/material-email-threat-detections/email-bomb-protection)** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupModeSetting"}},"required":["emailSync","fileSync","emailThreatRemediation","fileRemediation","sensitiveEmailRedaction","passwordResetProtection","oauthAppRemediation","emailBombProtection"]},"APIGroupBooleanSetting":{"title":"APIGroupBooleanSetting","type":"object","properties":{"enabled":{"description":"Whether the setting is enabled for this group in this tenant.","type":"boolean"},"source":{"description":"Which layer the effective value comes from: `group`, `tenant`, or `default`. Groups have no account layer. See [Settings Hierarchy](https://docs.material.security/learn-more/administration/settings-hierarchy) for how the layers resolve.","type":"string","enum":["group","tenant","default"]}},"required":["enabled","source"]},"APIGroupModeSetting":{"title":"APIGroupModeSetting","type":"object","properties":{"mode":{"description":"How [Email Bomb Protection](https://docs.material.security/learn-more/risk-areas/email-threats/detect/material-email-threat-detections/email-bomb-protection) is applied to this group's members in this tenant: `enabled` (detect and remediate), `detection_only` (detect without remediating), or `disabled`.","type":"string","enum":["enabled","detection_only","disabled"]},"source":{"description":"Which layer the effective value comes from: `group`, `tenant`, or `default`. Groups have no account layer. See [Settings Hierarchy](https://docs.material.security/learn-more/administration/settings-hierarchy) for how the layers resolve.","type":"string","enum":["group","tenant","default"]}},"required":["mode","source"]},"APIGroupLicenses":{"title":"APIGroupLicenses","type":"object","properties":{"values":{"description":"The licenses this group allocates to its members: `essentials` (Essentials), `advanced` (Advanced), or `ato_resilience` (ATO Resilience). A group allocates at most one tier, `essentials` or `advanced`, and can add `ato_resilience` alongside it.","type":"array","items":{"type":"string","enum":["essentials","advanced","ato_resilience"]}},"source":{"description":"Which layer the effective value comes from: `group`, `tenant`, or `default`. Groups have no account layer. See [Settings Hierarchy](https://docs.material.security/learn-more/administration/settings-hierarchy) for how the layers resolve.","type":"string","enum":["group","tenant","default"]}},"required":["values","source"]},"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/groups/{id}":{"get":{"operationId":"getGroup","summary":"Get Group","description":"Retrieves the full details of a single group by its encoded ID, including type, name, email, member count, licenses, and effective settings with their source.","tags":["Groups"],"parameters":[{"in":"path","name":"id","schema":{"description":"The encoded ID of the group to retrieve. Format: `grp.1.<base64>`.","type":"string","pattern":"^[a-z]{1,6}\\.[0-9]{1,2}\\.[A-Za-z0-9_-]+$"},"required":true,"description":"The encoded ID of the group to retrieve. Format: `grp.1.<base64>`."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/APIGroup"}}}},"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"}}}}}}}}}
```

## Update Group

> Updates a group's license allocation, per-group setting overrides, and the roles it grants its members. Name, email, membership, and provider settings are read-only, since they're synced from your provider. Only provided fields change, and a setting value of \`default\` clears the group override so it inherits from a higher level. Changing \`roles\` additionally requires role-management permission, and a tenant-scoped administrator can only grant roles they're allowed to bind themselves, within their own tenants. Be careful: roles granted here apply to every member of the group, and nothing stops you from removing the last Super Admin, which is irreversible without Material support.

```json
{"openapi":"3.1.0","info":{"title":"Material Security API","version":"v1"},"tags":[{"name":"Groups","description":"**Overview**\n\nThe Groups API provides programmatic access to the directory groups synced from your Google, Microsoft, or Okta tenant: Google groups, Google org units, Microsoft groups, and Okta groups. List and filter groups, retrieve one by its encoded ID, list a group's member accounts, and update its licenses, per-group setting overrides, and the roles it grants. Each group exposes its type, name, email, member count, licenses, and effective settings with the [layer they resolve from](https://docs.material.security/learn-more/administration/settings-hierarchy).\n\nFive endpoints make up the Groups API:\n\n* **[List Groups](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups)** (`GET /api/v1/groups`): filter, sort, and page through groups\n* **[Get Group](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups-id)** (`GET /api/v1/groups/{id}`): retrieve a single group by its encoded ID\n* **[List Group Members](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups-id-members)** (`GET /api/v1/groups/{id}/members`): retrieve the accounts that belong to a group\n* **[Update Group](https://docs.material.security/reference/api-v1/groups#patch-api-v1-groups-id)** (`PATCH /api/v1/groups/{id}`): update a group's licenses and setting overrides\n* **[Bulk Groups](https://docs.material.security/reference/api-v1/groups#post-api-v1-groups-bulk)** (`POST /api/v1/groups/bulk`): apply up to 200 group update operations in one request\n\n**Filtering**\n\nList accepts `search` (a loose match on name, description, email, or org-unit path), `email`, `type` (`okta`, `google_group`, `google_org_unit`, or `microsoft_group`), `memberOf` (encoded account IDs), `role`, and `hasOverrides`. Per-setting filters use dotted params, for example `setting.emailThreatRemediation=on`, and take `on`, `off`, or `overridden`. These match the group's own override rather than the value it inherits. Comma-separated values match any of the listed values within a single filter, and each filter you add narrows the result set further.\n\n**Sorting**\n\nSort with `?sort=<field>:asc|desc`. Supported fields: `name` (default) and `memberCount`.\n\n**Read-only fields**\n\nName, email, aliases, and membership are synced from your provider and can't be changed through this API. What you can write is `licenses`, `settings`, and `roles`. Setting a value to `default` clears the [group-level override](https://docs.material.security/learn-more/administration/group-and-account-customization) so the group inherits again.\n\nChanging `roles` additionally requires role-management permission. A [role](https://docs.material.security/learn-more/administration/admin-roles) granted here applies to every member of the group, and nothing stops you from removing the last Super Admin, which is irreversible without Material support.\n\n**Response Structure**\n\nList responses follow the standard two-part structure: a `meta` object (with `totalCount`, `limit`, `hasMore`, and `nextCursor`) and an `items` array.\n\nA group's `settings` is an array, not a single object. A group can span several tenants, and its own override is instance-wide, but what that override inherits differs per tenant, so the response carries one entry per tenant you can access, each with its own `settings` and `licenses` and the layer they resolve from. To read what the group itself overrides, which is what `PATCH` writes and what the `setting.<name>` and `hasOverrides` filters match, take the entries of any tenant whose `source` is `group`.\n\n**Bulk** responses return `results`, one entry per operation in request order, so `results[i]` corresponds to `operations[i]`, plus a `meta` object counting how many succeeded and failed. Operations are applied best-effort: a well-formed envelope always returns 200, and individual failures are reported in `results[]`.\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":{"UpdateGroupBody":{"title":"UpdateGroupBody","type":"object","properties":{"licenses":{"description":"The licenses this group allocates to its members.","$ref":"#/components/schemas/UpdateGroupLicenses"},"settings":{"description":"Per-group setting overrides. Only provided settings change. Name, email, and membership are read-only, since they're synced from your provider.","$ref":"#/components/schemas/UpdateGroupSettings"},"roles":{"description":"[Roles](https://docs.material.security/learn-more/administration/admin-roles) this group grants its members, to add or revoke. Requires role-management permission, and applies to every member of the group.","$ref":"#/components/schemas/UpdateRoles"}}},"UpdateGroupLicenses":{"title":"UpdateGroupLicenses","type":"object","properties":{"values":{"description":"The complete set of licenses the group should end up allocating, not a list of changes to apply. Include at most one tier, `essentials` (Essentials) or `advanced` (Advanced), and optionally `ato_resilience` (ATO Resilience) alongside it. Send `[]` to allocate none, or `\"default\"` to inherit from a higher level.","anyOf":[{"type":"array","items":{"type":"string","enum":["essentials","advanced","ato_resilience"]}},{"type":"string","const":"default"}]}}},"UpdateGroupSettings":{"title":"UpdateGroupSettings","type":"object","properties":{"emailSync":{"description":"Set `emailSync` to `on` or `off`, or to `default` to clear the group override so it inherits from a higher level.","type":"string","enum":["on","off","default"]},"fileSync":{"description":"Set `fileSync` to `on` or `off`, or to `default` to clear the group override so it inherits from a higher level.","type":"string","enum":["on","off","default"]},"emailThreatRemediation":{"description":"Set `emailThreatRemediation` to `on` or `off`, or to `default` to clear the group override so it inherits from a higher level.","type":"string","enum":["on","off","default"]},"fileRemediation":{"description":"Set `fileRemediation` to `on` or `off`, or to `default` to clear the group override so it inherits from a higher level.","type":"string","enum":["on","off","default"]},"sensitiveEmailRedaction":{"description":"Set `sensitiveEmailRedaction` to `on` or `off`, or to `default` to clear the group override so it inherits from a higher level.","type":"string","enum":["on","off","default"]},"passwordResetProtection":{"description":"Set `passwordResetProtection` to `on` or `off`, or to `default` to clear the group override so it inherits from a higher level.","type":"string","enum":["on","off","default"]},"oauthAppRemediation":{"description":"Set `oauthAppRemediation` to `on` or `off`, or to `default` to clear the group override so it inherits from a higher level.","type":"string","enum":["on","off","default"]},"emailBombProtection":{"description":"Set `emailBombProtection` to `enabled`, `detection_only`, or `disabled`, or to `default` to clear the group override so it inherits from a higher level.","type":"string","enum":["enabled","detection_only","disabled","default"]}}},"UpdateRoles":{"title":"UpdateRoles","description":"Role assignment changes. Only roles named in `assign` or `remove` are affected, so this is not a full-set replacement. Be careful: nothing stops you from removing your own access or the last Super Admin, and either is irreversible without Material support.","type":"object","properties":{"assign":{"description":"Roles to grant. Only the listed roles are touched.","type":"array","items":{"$ref":"#/components/schemas/APIRoleAssignment"}},"remove":{"description":"Roles to revoke, at every scope the account or group holds them. There is no per-tenant removal, so to narrow a role rather than drop it, re-assign it with a shorter `tenants` list instead. Removing a role that isn't held does nothing, and a role inherited from a group must be removed on that group. Listing an ID in both `assign` and `remove` returns a 400.","type":"array","items":{"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"]}}}},"APIRoleAssignment":{"title":"APIRoleAssignment","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"]},"tenants":{"description":"Tenants to grant the role in, as encoded tenant IDs (format `tnt.1.<base64>`). Required for tenant-scoped IDs, rejected for the others. Assigning a tenant-scoped role the account or group already holds replaces its tenant list.","type":"array","items":{"type":"string","pattern":"^[a-z]{1,6}\\.[0-9]{1,2}\\.[A-Za-z0-9_-]+$"}}},"required":["id"]},"APIGroup":{"title":"APIGroup","description":"A directory group (Google group, Google org unit, Microsoft group, or Okta group) synced from your provider. A group can span several tenants and its own override is instance-wide, so `settings` reports how that override resolves inside each tenant your token can access.","type":"object","properties":{"id":{"description":"The encoded group ID. Format: `grp.1.<base64>`.","type":"string"},"type":{"description":"The kind of directory group: `okta` (Okta), `google_group` (Google Group), `google_org_unit` (Google Org Unit), or `microsoft_group` (Microsoft Group).","type":"string","enum":["okta","google_group","google_org_unit","microsoft_group"]},"name":{"description":"The group's display name.","type":"string"},"description":{"description":"The group's description. An empty string if it has none.","type":"string"},"email":{"description":"The group's primary email address. Null for Okta groups and Google org units, which have none.","anyOf":[{"type":"string"},{"type":"null"}]},"aliases":{"description":"Additional email addresses that reach this group.","type":"array","items":{"type":"string"}},"memberCount":{"description":"Estimated number of accounts in the group.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"roles":{"description":"The [roles](https://docs.material.security/learn-more/administration/admin-roles) this group grants to every one of its members. Empty if the group grants none. Members see these on their own account with `source: \"group\"`.","type":"array","items":{"$ref":"#/components/schemas/APIGroupAssignedRole"}},"settings":{"description":"Settings and licenses resolved per tenant, with one entry per tenant your token can access, ordered by tenant ID. Empty when your token can access none of them. To read what the group itself overrides, which is what `PATCH` writes and what the `setting.<name>` and `hasOverrides` filters match, take the entries of any tenant whose `source` is `group`.","type":"array","items":{"$ref":"#/components/schemas/APIGroupTenantSettings"}},"lastUpdatedAt":{"description":"When Material last synced this group, in ISO 8601 format. Null if it has never synced.","anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["id","type","name","description","email","aliases","memberCount","roles","settings","lastUpdatedAt"]},"APIGroupAssignedRole":{"title":"APIGroupAssignedRole","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"]},"tenants":{"description":"Tenants the role applies to, as encoded tenant IDs (format `tnt.1.<base64>`), for tenant-scoped IDs only. `\"all\"` means the role was granted across every tenant, which you can read but not assign through this API.","anyOf":[{"type":"array","items":{"type":"string"}},{"type":"string","const":"all"}]}},"required":["id"]},"APIGroupTenantSettings":{"title":"APIGroupTenantSettings","type":"object","properties":{"tenant":{"description":"The tenant these values are resolved in, as an encoded tenant ID (format `tnt.1.<base64>`).","type":"string"},"settings":{"$ref":"#/components/schemas/APIGroupSettings"},"licenses":{"$ref":"#/components/schemas/APIGroupLicenses"}},"required":["tenant","settings","licenses"]},"APIGroupSettings":{"title":"APIGroupSettings","description":"Each product setting's effective value for this group in one tenant, with the layer it resolves from. See [Group and Account Customization](https://docs.material.security/learn-more/administration/group-and-account-customization) for how overrides work.","type":"object","properties":{"emailSync":{"title":"APIGroupBooleanSetting","description":"Whether Material syncs members' mailboxes. Shown as **Mailbox Syncing** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"fileSync":{"title":"APIGroupBooleanSetting","description":"Whether Material syncs members' Google Drive files. Shown as **My Drive Syncing** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"emailThreatRemediation":{"title":"APIGroupBooleanSetting","description":"Whether Material remediates email threats found in members' mailboxes. Shown as **Email Threat Remediation** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"fileRemediation":{"title":"APIGroupBooleanSetting","description":"Whether Material remediates risky sharing on members' files. Shown as **File Remediation** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"sensitiveEmailRedaction":{"title":"APIGroupBooleanSetting","description":"Whether Material redacts sensitive email in members' mailboxes. Shown as **Sensitive Email Redaction** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"passwordResetProtection":{"title":"APIGroupBooleanSetting","description":"Whether Material holds password reset and app signup email for members during a lockdown. Shown as **Password Reset & App Signup Protection** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"oauthAppRemediation":{"title":"APIGroupBooleanSetting","description":"Whether Material revokes members' grants when an OAuth app carries a revoke policy. Shown as **OAuth App Remediation** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"emailBombProtection":{"title":"APIGroupModeSetting","description":"How Material handles a sudden surge of email to a member. Shown as **[Email Bomb Protection](https://docs.material.security/learn-more/risk-areas/email-threats/detect/material-email-threat-detections/email-bomb-protection)** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupModeSetting"}},"required":["emailSync","fileSync","emailThreatRemediation","fileRemediation","sensitiveEmailRedaction","passwordResetProtection","oauthAppRemediation","emailBombProtection"]},"APIGroupBooleanSetting":{"title":"APIGroupBooleanSetting","type":"object","properties":{"enabled":{"description":"Whether the setting is enabled for this group in this tenant.","type":"boolean"},"source":{"description":"Which layer the effective value comes from: `group`, `tenant`, or `default`. Groups have no account layer. See [Settings Hierarchy](https://docs.material.security/learn-more/administration/settings-hierarchy) for how the layers resolve.","type":"string","enum":["group","tenant","default"]}},"required":["enabled","source"]},"APIGroupModeSetting":{"title":"APIGroupModeSetting","type":"object","properties":{"mode":{"description":"How [Email Bomb Protection](https://docs.material.security/learn-more/risk-areas/email-threats/detect/material-email-threat-detections/email-bomb-protection) is applied to this group's members in this tenant: `enabled` (detect and remediate), `detection_only` (detect without remediating), or `disabled`.","type":"string","enum":["enabled","detection_only","disabled"]},"source":{"description":"Which layer the effective value comes from: `group`, `tenant`, or `default`. Groups have no account layer. See [Settings Hierarchy](https://docs.material.security/learn-more/administration/settings-hierarchy) for how the layers resolve.","type":"string","enum":["group","tenant","default"]}},"required":["mode","source"]},"APIGroupLicenses":{"title":"APIGroupLicenses","type":"object","properties":{"values":{"description":"The licenses this group allocates to its members: `essentials` (Essentials), `advanced` (Advanced), or `ato_resilience` (ATO Resilience). A group allocates at most one tier, `essentials` or `advanced`, and can add `ato_resilience` alongside it.","type":"array","items":{"type":"string","enum":["essentials","advanced","ato_resilience"]}},"source":{"description":"Which layer the effective value comes from: `group`, `tenant`, or `default`. Groups have no account layer. See [Settings Hierarchy](https://docs.material.security/learn-more/administration/settings-hierarchy) for how the layers resolve.","type":"string","enum":["group","tenant","default"]}},"required":["values","source"]},"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/groups/{id}":{"patch":{"operationId":"patchGroup","summary":"Update Group","description":"Updates a group's license allocation, per-group setting overrides, and the roles it grants its members. Name, email, membership, and provider settings are read-only, since they're synced from your provider. Only provided fields change, and a setting value of `default` clears the group override so it inherits from a higher level. Changing `roles` additionally requires role-management permission, and a tenant-scoped administrator can only grant roles they're allowed to bind themselves, within their own tenants. Be careful: roles granted here apply to every member of the group, and nothing stops you from removing the last Super Admin, which is irreversible without Material support.","tags":["Groups"],"parameters":[{"in":"path","name":"id","schema":{"description":"The encoded ID of the group to retrieve. Format: `grp.1.<base64>`.","type":"string","pattern":"^[a-z]{1,6}\\.[0-9]{1,2}\\.[A-Za-z0-9_-]+$"},"required":true,"description":"The encoded ID of the group to retrieve. Format: `grp.1.<base64>`."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGroupBody"}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/APIGroup"}}}},"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"}}}}}}}}}
```

## List Group Members

> Retrieves the paginated list of accounts that belong to a specific group. Each member is returned as a full account object, equivalent to filtering the accounts list by this group.

```json
{"openapi":"3.1.0","info":{"title":"Material Security API","version":"v1"},"tags":[{"name":"Groups","description":"**Overview**\n\nThe Groups API provides programmatic access to the directory groups synced from your Google, Microsoft, or Okta tenant: Google groups, Google org units, Microsoft groups, and Okta groups. List and filter groups, retrieve one by its encoded ID, list a group's member accounts, and update its licenses, per-group setting overrides, and the roles it grants. Each group exposes its type, name, email, member count, licenses, and effective settings with the [layer they resolve from](https://docs.material.security/learn-more/administration/settings-hierarchy).\n\nFive endpoints make up the Groups API:\n\n* **[List Groups](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups)** (`GET /api/v1/groups`): filter, sort, and page through groups\n* **[Get Group](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups-id)** (`GET /api/v1/groups/{id}`): retrieve a single group by its encoded ID\n* **[List Group Members](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups-id-members)** (`GET /api/v1/groups/{id}/members`): retrieve the accounts that belong to a group\n* **[Update Group](https://docs.material.security/reference/api-v1/groups#patch-api-v1-groups-id)** (`PATCH /api/v1/groups/{id}`): update a group's licenses and setting overrides\n* **[Bulk Groups](https://docs.material.security/reference/api-v1/groups#post-api-v1-groups-bulk)** (`POST /api/v1/groups/bulk`): apply up to 200 group update operations in one request\n\n**Filtering**\n\nList accepts `search` (a loose match on name, description, email, or org-unit path), `email`, `type` (`okta`, `google_group`, `google_org_unit`, or `microsoft_group`), `memberOf` (encoded account IDs), `role`, and `hasOverrides`. Per-setting filters use dotted params, for example `setting.emailThreatRemediation=on`, and take `on`, `off`, or `overridden`. These match the group's own override rather than the value it inherits. Comma-separated values match any of the listed values within a single filter, and each filter you add narrows the result set further.\n\n**Sorting**\n\nSort with `?sort=<field>:asc|desc`. Supported fields: `name` (default) and `memberCount`.\n\n**Read-only fields**\n\nName, email, aliases, and membership are synced from your provider and can't be changed through this API. What you can write is `licenses`, `settings`, and `roles`. Setting a value to `default` clears the [group-level override](https://docs.material.security/learn-more/administration/group-and-account-customization) so the group inherits again.\n\nChanging `roles` additionally requires role-management permission. A [role](https://docs.material.security/learn-more/administration/admin-roles) granted here applies to every member of the group, and nothing stops you from removing the last Super Admin, which is irreversible without Material support.\n\n**Response Structure**\n\nList responses follow the standard two-part structure: a `meta` object (with `totalCount`, `limit`, `hasMore`, and `nextCursor`) and an `items` array.\n\nA group's `settings` is an array, not a single object. A group can span several tenants, and its own override is instance-wide, but what that override inherits differs per tenant, so the response carries one entry per tenant you can access, each with its own `settings` and `licenses` and the layer they resolve from. To read what the group itself overrides, which is what `PATCH` writes and what the `setting.<name>` and `hasOverrides` filters match, take the entries of any tenant whose `source` is `group`.\n\n**Bulk** responses return `results`, one entry per operation in request order, so `results[i]` corresponds to `operations[i]`, plus a `meta` object counting how many succeeded and failed. Operations are applied best-effort: a well-formed envelope always returns 200, and individual failures are reported in `results[]`.\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":{"APIAccountCollection":{"title":"APIAccountCollection","type":"object","properties":{"meta":{"$ref":"#/components/schemas/CollectionMeta"},"items":{"type":"array","items":{"$ref":"#/components/schemas/APIAccount"}}},"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"}]}}},"APIAccount":{"title":"APIAccount","description":"A directory account (person or mailbox) synced from Google or Microsoft.","type":"object","properties":{"id":{"description":"The encoded account ID. Format: `acct.1.<base64>`.","type":"string"},"type":{"description":"The provider the account is synced from: `google` or `microsoft`.","type":"string","enum":["google","microsoft"]},"displayName":{"description":"Display name of the account holder.","type":"string"},"givenName":{"description":"Given (first) name; null if unavailable.","anyOf":[{"type":"string"},{"type":"null"}]},"familyName":{"description":"Family (last) name; null if unavailable.","anyOf":[{"type":"string"},{"type":"null"}]},"email":{"description":"Primary email address.","type":"string"},"aliases":{"description":"Additional email aliases.","type":"array","items":{"type":"string"}},"organization":{"description":"The organization on the account's directory record. Read-only, and null if your provider doesn't supply one.","anyOf":[{"type":"string"},{"type":"null"}]},"vip":{"$ref":"#/components/schemas/APIVip"},"licenses":{"$ref":"#/components/schemas/APILicenses"},"roles":{"description":"The [roles](https://docs.material.security/learn-more/administration/admin-roles) in effect on this account, both assigned directly and inherited from groups. A role held at a broader scope hides the narrower assignments it supersedes, so this reflects effective access rather than every assignment on record. Empty if the account has no roles. Roles are scoped to this account, so if one person owns several accounts, each reports only its own roles, matching the `role` filter.","type":"array","items":{"$ref":"#/components/schemas/APIAssignedRole"}},"settings":{"$ref":"#/components/schemas/APIAccountSettings"},"mailbox":{"$ref":"#/components/schemas/APIAccountMailbox"},"providerStatus":{"description":"The account's state at your provider: `active`, `suspended`, `archived`, or `deleted`.","type":"string","enum":["active","suspended","archived","deleted"]},"lastSyncedAt":{"description":"When Material last synced this account, in ISO 8601 format. Null if it has never synced.","anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"groups":{"description":"Group memberships; populated only when `include=groups`.","type":"object","properties":{"meta":{"$ref":"#/components/schemas/CollectionMeta"},"items":{"type":"array","items":{"$ref":"#/components/schemas/APIGroupRef"}}},"required":["meta","items"]}},"required":["id","type","displayName","givenName","familyName","email","aliases","organization","vip","licenses","roles","settings","mailbox","providerStatus","lastSyncedAt"]},"APIVip":{"title":"APIVip","type":"object","properties":{"enabled":{"description":"Whether the account is marked as a [VIP](https://docs.material.security/learn-more/risk-areas/email-threats/detect/vip-impersonation).","type":"boolean"},"emailAliases":{"description":"Additional email aliases treated as this VIP.","type":"array","items":{"type":"string"}},"displayNames":{"description":"Additional display names treated as this VIP.","type":"array","items":{"type":"string"}}},"required":["enabled","emailAliases","displayNames"]},"APILicenses":{"title":"APILicenses","type":"object","properties":{"values":{"description":"The licenses active on this account: `essentials` (Essentials), `advanced` (Advanced), or `ato_resilience` (ATO Resilience). An account carries at most one tier, `essentials` or `advanced`, and can add `ato_resilience` alongside it.","type":"array","items":{"type":"string","enum":["essentials","advanced","ato_resilience"]}},"source":{"description":"Which layer the effective value comes from: `account`, `group`, `tenant`, or `default`. See [Settings Hierarchy](https://docs.material.security/learn-more/administration/settings-hierarchy) for how the layers resolve.","type":"string","enum":["account","group","tenant","default"]},"sourceGroups":{"description":"The group(s) responsible for the value; present only when `source` is `group`.","type":"array","items":{"$ref":"#/components/schemas/APIGroupRef"}},"sourceTenant":{"description":"The tenant responsible for the value, as an encoded tenant ID (format `tnt.1.<base64>`). Present only when `source` is `tenant`.","type":"string"},"requireMailbox":{"title":"APIBooleanSetting","description":"Whether an account needs a provisioned mailbox before Material assigns it a license. Shown as **Require mailbox for license assignment** on an account's **Settings** tab.","$ref":"#/components/schemas/APIBooleanSetting"}},"required":["values","source","requireMailbox"]},"APIGroupRef":{"title":"APIGroupRef","type":"object","properties":{"id":{"description":"The encoded group ID. Format: `grp.1.<base64>`.","type":"string"},"name":{"description":"The group's display name. Null if Material doesn't have one.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name"]},"APIBooleanSetting":{"title":"APIBooleanSetting","type":"object","properties":{"enabled":{"description":"Whether the setting is enabled for this account.","type":"boolean"},"source":{"description":"Which layer the effective value comes from: `account`, `group`, `tenant`, or `default`. See [Settings Hierarchy](https://docs.material.security/learn-more/administration/settings-hierarchy) for how the layers resolve.","type":"string","enum":["account","group","tenant","default"]},"sourceGroups":{"description":"The group(s) responsible for the value; present only when `source` is `group`.","type":"array","items":{"$ref":"#/components/schemas/APIGroupRef"}},"sourceTenant":{"description":"The tenant responsible for the value, as an encoded tenant ID (format `tnt.1.<base64>`). Present only when `source` is `tenant`.","type":"string"}},"required":["enabled","source"]},"APIAssignedRole":{"title":"APIAssignedRole","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"]},"tenants":{"description":"Tenants the role applies to, as encoded tenant IDs (format `tnt.1.<base64>`), for tenant-scoped IDs only. `\"all\"` means the role was granted across every tenant, which you can read but not assign through this API.","anyOf":[{"type":"array","items":{"type":"string"}},{"type":"string","const":"all"}]},"source":{"description":"Where the assignment comes from: `direct` (on this account), `group` (inherited from `groupId`, and changeable only on that group), or `tenant` (granted to everyone in the tenant).","type":"string","enum":["direct","group","tenant"]},"groupId":{"description":"The granting group; present only when `source` is `group`.","type":"string"}},"required":["id","source"]},"APIAccountSettings":{"title":"APIAccountSettings","description":"Each product setting's effective value for this account, with the layer it resolves from. See [Group and Account Customization](https://docs.material.security/learn-more/administration/group-and-account-customization) for how overrides work.","type":"object","properties":{"emailSync":{"title":"APIBooleanSetting","description":"Whether Material syncs this account's mailbox. Shown as **Mailbox Syncing** on an account's **Settings** tab.","$ref":"#/components/schemas/APIBooleanSetting"},"fileSync":{"title":"APIBooleanSetting","description":"Whether Material syncs this account's Google Drive files. Shown as **My Drive Syncing** on an account's **Settings** tab.","$ref":"#/components/schemas/APIBooleanSetting"},"emailThreatRemediation":{"title":"APIBooleanSetting","description":"Whether Material remediates email threats found in this mailbox. Shown as **Email Threat Remediation** on an account's **Settings** tab.","$ref":"#/components/schemas/APIBooleanSetting"},"fileRemediation":{"title":"APIBooleanSetting","description":"Whether Material remediates risky sharing on this account's files. Shown as **File Remediation** on an account's **Settings** tab.","$ref":"#/components/schemas/APIBooleanSetting"},"sensitiveEmailRedaction":{"title":"APIBooleanSetting","description":"Whether Material redacts sensitive email in this mailbox. Shown as **Sensitive Email Redaction** on an account's **Settings** tab.","$ref":"#/components/schemas/APIBooleanSetting"},"passwordResetProtection":{"title":"APIBooleanSetting","description":"Whether Material holds password reset and app signup email for this account during a lockdown. Shown as **Password Reset & App Signup Protection** on an account's **Settings** tab.","$ref":"#/components/schemas/APIBooleanSetting"},"oauthAppRemediation":{"title":"APIBooleanSetting","description":"Whether Material revokes this account's grants when an OAuth app carries a revoke policy. Shown as **OAuth App Remediation** on an account's **Settings** tab.","$ref":"#/components/schemas/APIBooleanSetting"},"emailBombProtection":{"title":"APIModeSetting","description":"How Material handles a sudden surge of email to this account. Shown as **[Email Bomb Protection](https://docs.material.security/learn-more/risk-areas/email-threats/detect/material-email-threat-detections/email-bomb-protection)** on an account's **Settings** tab.","$ref":"#/components/schemas/APIModeSetting"}},"required":["emailSync","fileSync","emailThreatRemediation","fileRemediation","sensitiveEmailRedaction","passwordResetProtection","oauthAppRemediation","emailBombProtection"]},"APIModeSetting":{"title":"APIModeSetting","type":"object","properties":{"mode":{"description":"How [Email Bomb Protection](https://docs.material.security/learn-more/risk-areas/email-threats/detect/material-email-threat-detections/email-bomb-protection) is applied to this account: `enabled` (detect and remediate), `detection_only` (detect without remediating), or `disabled`.","type":"string","enum":["enabled","detection_only","disabled"]},"source":{"description":"Which layer the effective value comes from: `account`, `group`, `tenant`, or `default`. See [Settings Hierarchy](https://docs.material.security/learn-more/administration/settings-hierarchy) for how the layers resolve.","type":"string","enum":["account","group","tenant","default"]},"sourceGroups":{"description":"The group(s) responsible for the value; present only when `source` is `group`.","type":"array","items":{"$ref":"#/components/schemas/APIGroupRef"}},"sourceTenant":{"description":"The tenant responsible for the value, as an encoded tenant ID (format `tnt.1.<base64>`). Present only when `source` is `tenant`.","type":"string"}},"required":["mode","source"]},"APIAccountMailbox":{"title":"APIAccountMailbox","type":"object","properties":{"status":{"description":"Whether the account's mailbox is `enabled` or `disabled`. Null when Material hasn't synced the mailbox or can't determine its state.","anyOf":[{"type":"string","enum":["enabled","disabled"]},{"type":"null"}]},"messageCount":{"description":"Approximate number of messages in the mailbox. Null if unknown.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["status","messageCount"]},"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/groups/{id}/members":{"get":{"operationId":"listGroupMembers","summary":"List Group Members","description":"Retrieves the paginated list of accounts that belong to a specific group. Each member is returned as a full account object, equivalent to filtering the accounts list by this group.","tags":["Groups"],"parameters":[{"in":"path","name":"id","schema":{"description":"The encoded ID of the group to retrieve. Format: `grp.1.<base64>`.","type":"string","pattern":"^[a-z]{1,6}\\.[0-9]{1,2}\\.[A-Za-z0-9_-]+$"},"required":true,"description":"The encoded ID of the group to retrieve. Format: `grp.1.<base64>`."},{"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/APIAccountCollection"}}}},"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"}}}}}}}}}
```

## Bulk Groups

> Applies up to 200 group update operations in one request, best-effort with per-item results in request order (\`results\[i]\` corresponds to \`operations\[i]\`). A well-formed envelope always returns 200; individual failures are reported in \`results\[]\`.

```json
{"openapi":"3.1.0","info":{"title":"Material Security API","version":"v1"},"tags":[{"name":"Groups","description":"**Overview**\n\nThe Groups API provides programmatic access to the directory groups synced from your Google, Microsoft, or Okta tenant: Google groups, Google org units, Microsoft groups, and Okta groups. List and filter groups, retrieve one by its encoded ID, list a group's member accounts, and update its licenses, per-group setting overrides, and the roles it grants. Each group exposes its type, name, email, member count, licenses, and effective settings with the [layer they resolve from](https://docs.material.security/learn-more/administration/settings-hierarchy).\n\nFive endpoints make up the Groups API:\n\n* **[List Groups](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups)** (`GET /api/v1/groups`): filter, sort, and page through groups\n* **[Get Group](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups-id)** (`GET /api/v1/groups/{id}`): retrieve a single group by its encoded ID\n* **[List Group Members](https://docs.material.security/reference/api-v1/groups#get-api-v1-groups-id-members)** (`GET /api/v1/groups/{id}/members`): retrieve the accounts that belong to a group\n* **[Update Group](https://docs.material.security/reference/api-v1/groups#patch-api-v1-groups-id)** (`PATCH /api/v1/groups/{id}`): update a group's licenses and setting overrides\n* **[Bulk Groups](https://docs.material.security/reference/api-v1/groups#post-api-v1-groups-bulk)** (`POST /api/v1/groups/bulk`): apply up to 200 group update operations in one request\n\n**Filtering**\n\nList accepts `search` (a loose match on name, description, email, or org-unit path), `email`, `type` (`okta`, `google_group`, `google_org_unit`, or `microsoft_group`), `memberOf` (encoded account IDs), `role`, and `hasOverrides`. Per-setting filters use dotted params, for example `setting.emailThreatRemediation=on`, and take `on`, `off`, or `overridden`. These match the group's own override rather than the value it inherits. Comma-separated values match any of the listed values within a single filter, and each filter you add narrows the result set further.\n\n**Sorting**\n\nSort with `?sort=<field>:asc|desc`. Supported fields: `name` (default) and `memberCount`.\n\n**Read-only fields**\n\nName, email, aliases, and membership are synced from your provider and can't be changed through this API. What you can write is `licenses`, `settings`, and `roles`. Setting a value to `default` clears the [group-level override](https://docs.material.security/learn-more/administration/group-and-account-customization) so the group inherits again.\n\nChanging `roles` additionally requires role-management permission. A [role](https://docs.material.security/learn-more/administration/admin-roles) granted here applies to every member of the group, and nothing stops you from removing the last Super Admin, which is irreversible without Material support.\n\n**Response Structure**\n\nList responses follow the standard two-part structure: a `meta` object (with `totalCount`, `limit`, `hasMore`, and `nextCursor`) and an `items` array.\n\nA group's `settings` is an array, not a single object. A group can span several tenants, and its own override is instance-wide, but what that override inherits differs per tenant, so the response carries one entry per tenant you can access, each with its own `settings` and `licenses` and the layer they resolve from. To read what the group itself overrides, which is what `PATCH` writes and what the `setting.<name>` and `hasOverrides` filters match, take the entries of any tenant whose `source` is `group`.\n\n**Bulk** responses return `results`, one entry per operation in request order, so `results[i]` corresponds to `operations[i]`, plus a `meta` object counting how many succeeded and failed. Operations are applied best-effort: a well-formed envelope always returns 200, and individual failures are reported in `results[]`.\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":{"BulkGroupsBody":{"title":"BulkGroupsBody","type":"object","properties":{"operations":{"description":"Up to 200 operations, applied best-effort with per-item results.","minItems":1,"maxItems":200,"type":"array","items":{"$ref":"#/components/schemas/BulkGroupOperation"}}},"required":["operations"]},"BulkGroupOperation":{"title":"BulkGroupOperation","type":"object","properties":{"method":{"description":"The operation to apply. Only `update` is supported.","type":"string","const":"update"},"id":{"description":"The encoded ID of the group to update.","type":"string","pattern":"^[a-z]{1,6}\\.[0-9]{1,2}\\.[A-Za-z0-9_-]+$"},"body":{"$ref":"#/components/schemas/UpdateGroupBody"}},"required":["method","id","body"]},"UpdateGroupBody":{"title":"UpdateGroupBody","type":"object","properties":{"licenses":{"description":"The licenses this group allocates to its members.","$ref":"#/components/schemas/UpdateGroupLicenses"},"settings":{"description":"Per-group setting overrides. Only provided settings change. Name, email, and membership are read-only, since they're synced from your provider.","$ref":"#/components/schemas/UpdateGroupSettings"},"roles":{"description":"[Roles](https://docs.material.security/learn-more/administration/admin-roles) this group grants its members, to add or revoke. Requires role-management permission, and applies to every member of the group.","$ref":"#/components/schemas/UpdateRoles"}}},"UpdateGroupLicenses":{"title":"UpdateGroupLicenses","type":"object","properties":{"values":{"description":"The complete set of licenses the group should end up allocating, not a list of changes to apply. Include at most one tier, `essentials` (Essentials) or `advanced` (Advanced), and optionally `ato_resilience` (ATO Resilience) alongside it. Send `[]` to allocate none, or `\"default\"` to inherit from a higher level.","anyOf":[{"type":"array","items":{"type":"string","enum":["essentials","advanced","ato_resilience"]}},{"type":"string","const":"default"}]}}},"UpdateGroupSettings":{"title":"UpdateGroupSettings","type":"object","properties":{"emailSync":{"description":"Set `emailSync` to `on` or `off`, or to `default` to clear the group override so it inherits from a higher level.","type":"string","enum":["on","off","default"]},"fileSync":{"description":"Set `fileSync` to `on` or `off`, or to `default` to clear the group override so it inherits from a higher level.","type":"string","enum":["on","off","default"]},"emailThreatRemediation":{"description":"Set `emailThreatRemediation` to `on` or `off`, or to `default` to clear the group override so it inherits from a higher level.","type":"string","enum":["on","off","default"]},"fileRemediation":{"description":"Set `fileRemediation` to `on` or `off`, or to `default` to clear the group override so it inherits from a higher level.","type":"string","enum":["on","off","default"]},"sensitiveEmailRedaction":{"description":"Set `sensitiveEmailRedaction` to `on` or `off`, or to `default` to clear the group override so it inherits from a higher level.","type":"string","enum":["on","off","default"]},"passwordResetProtection":{"description":"Set `passwordResetProtection` to `on` or `off`, or to `default` to clear the group override so it inherits from a higher level.","type":"string","enum":["on","off","default"]},"oauthAppRemediation":{"description":"Set `oauthAppRemediation` to `on` or `off`, or to `default` to clear the group override so it inherits from a higher level.","type":"string","enum":["on","off","default"]},"emailBombProtection":{"description":"Set `emailBombProtection` to `enabled`, `detection_only`, or `disabled`, or to `default` to clear the group override so it inherits from a higher level.","type":"string","enum":["enabled","detection_only","disabled","default"]}}},"UpdateRoles":{"title":"UpdateRoles","description":"Role assignment changes. Only roles named in `assign` or `remove` are affected, so this is not a full-set replacement. Be careful: nothing stops you from removing your own access or the last Super Admin, and either is irreversible without Material support.","type":"object","properties":{"assign":{"description":"Roles to grant. Only the listed roles are touched.","type":"array","items":{"$ref":"#/components/schemas/APIRoleAssignment"}},"remove":{"description":"Roles to revoke, at every scope the account or group holds them. There is no per-tenant removal, so to narrow a role rather than drop it, re-assign it with a shorter `tenants` list instead. Removing a role that isn't held does nothing, and a role inherited from a group must be removed on that group. Listing an ID in both `assign` and `remove` returns a 400.","type":"array","items":{"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"]}}}},"APIRoleAssignment":{"title":"APIRoleAssignment","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"]},"tenants":{"description":"Tenants to grant the role in, as encoded tenant IDs (format `tnt.1.<base64>`). Required for tenant-scoped IDs, rejected for the others. Assigning a tenant-scoped role the account or group already holds replaces its tenant list.","type":"array","items":{"type":"string","pattern":"^[a-z]{1,6}\\.[0-9]{1,2}\\.[A-Za-z0-9_-]+$"}}},"required":["id"]},"BulkGroupsResponse":{"title":"BulkGroupsResponse","type":"object","properties":{"results":{"description":"Per-operation result, in the same order as the request.","type":"array","items":{"oneOf":[{"type":"object","properties":{"status":{"type":"string","const":"ok"},"index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"id":{"type":"string"},"group":{"$ref":"#/components/schemas/APIGroup"}},"required":["status","index","id","group"]},{"type":"object","properties":{"status":{"type":"string","const":"error"},"index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"id":{"type":"string"},"error":{"type":"string"}},"required":["status","index","id","error"]}],"type":"object"}},"meta":{"description":"Aggregate counts across all operations.","type":"object","properties":{"succeeded":{"description":"Number of operations that succeeded.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"failed":{"description":"Number of operations that failed.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["succeeded","failed"]}},"required":["results","meta"]},"APIGroup":{"title":"APIGroup","description":"A directory group (Google group, Google org unit, Microsoft group, or Okta group) synced from your provider. A group can span several tenants and its own override is instance-wide, so `settings` reports how that override resolves inside each tenant your token can access.","type":"object","properties":{"id":{"description":"The encoded group ID. Format: `grp.1.<base64>`.","type":"string"},"type":{"description":"The kind of directory group: `okta` (Okta), `google_group` (Google Group), `google_org_unit` (Google Org Unit), or `microsoft_group` (Microsoft Group).","type":"string","enum":["okta","google_group","google_org_unit","microsoft_group"]},"name":{"description":"The group's display name.","type":"string"},"description":{"description":"The group's description. An empty string if it has none.","type":"string"},"email":{"description":"The group's primary email address. Null for Okta groups and Google org units, which have none.","anyOf":[{"type":"string"},{"type":"null"}]},"aliases":{"description":"Additional email addresses that reach this group.","type":"array","items":{"type":"string"}},"memberCount":{"description":"Estimated number of accounts in the group.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"roles":{"description":"The [roles](https://docs.material.security/learn-more/administration/admin-roles) this group grants to every one of its members. Empty if the group grants none. Members see these on their own account with `source: \"group\"`.","type":"array","items":{"$ref":"#/components/schemas/APIGroupAssignedRole"}},"settings":{"description":"Settings and licenses resolved per tenant, with one entry per tenant your token can access, ordered by tenant ID. Empty when your token can access none of them. To read what the group itself overrides, which is what `PATCH` writes and what the `setting.<name>` and `hasOverrides` filters match, take the entries of any tenant whose `source` is `group`.","type":"array","items":{"$ref":"#/components/schemas/APIGroupTenantSettings"}},"lastUpdatedAt":{"description":"When Material last synced this group, in ISO 8601 format. Null if it has never synced.","anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["id","type","name","description","email","aliases","memberCount","roles","settings","lastUpdatedAt"]},"APIGroupAssignedRole":{"title":"APIGroupAssignedRole","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"]},"tenants":{"description":"Tenants the role applies to, as encoded tenant IDs (format `tnt.1.<base64>`), for tenant-scoped IDs only. `\"all\"` means the role was granted across every tenant, which you can read but not assign through this API.","anyOf":[{"type":"array","items":{"type":"string"}},{"type":"string","const":"all"}]}},"required":["id"]},"APIGroupTenantSettings":{"title":"APIGroupTenantSettings","type":"object","properties":{"tenant":{"description":"The tenant these values are resolved in, as an encoded tenant ID (format `tnt.1.<base64>`).","type":"string"},"settings":{"$ref":"#/components/schemas/APIGroupSettings"},"licenses":{"$ref":"#/components/schemas/APIGroupLicenses"}},"required":["tenant","settings","licenses"]},"APIGroupSettings":{"title":"APIGroupSettings","description":"Each product setting's effective value for this group in one tenant, with the layer it resolves from. See [Group and Account Customization](https://docs.material.security/learn-more/administration/group-and-account-customization) for how overrides work.","type":"object","properties":{"emailSync":{"title":"APIGroupBooleanSetting","description":"Whether Material syncs members' mailboxes. Shown as **Mailbox Syncing** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"fileSync":{"title":"APIGroupBooleanSetting","description":"Whether Material syncs members' Google Drive files. Shown as **My Drive Syncing** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"emailThreatRemediation":{"title":"APIGroupBooleanSetting","description":"Whether Material remediates email threats found in members' mailboxes. Shown as **Email Threat Remediation** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"fileRemediation":{"title":"APIGroupBooleanSetting","description":"Whether Material remediates risky sharing on members' files. Shown as **File Remediation** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"sensitiveEmailRedaction":{"title":"APIGroupBooleanSetting","description":"Whether Material redacts sensitive email in members' mailboxes. Shown as **Sensitive Email Redaction** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"passwordResetProtection":{"title":"APIGroupBooleanSetting","description":"Whether Material holds password reset and app signup email for members during a lockdown. Shown as **Password Reset & App Signup Protection** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"oauthAppRemediation":{"title":"APIGroupBooleanSetting","description":"Whether Material revokes members' grants when an OAuth app carries a revoke policy. Shown as **OAuth App Remediation** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupBooleanSetting"},"emailBombProtection":{"title":"APIGroupModeSetting","description":"How Material handles a sudden surge of email to a member. Shown as **[Email Bomb Protection](https://docs.material.security/learn-more/risk-areas/email-threats/detect/material-email-threat-detections/email-bomb-protection)** on a group's **Settings** tab.","$ref":"#/components/schemas/APIGroupModeSetting"}},"required":["emailSync","fileSync","emailThreatRemediation","fileRemediation","sensitiveEmailRedaction","passwordResetProtection","oauthAppRemediation","emailBombProtection"]},"APIGroupBooleanSetting":{"title":"APIGroupBooleanSetting","type":"object","properties":{"enabled":{"description":"Whether the setting is enabled for this group in this tenant.","type":"boolean"},"source":{"description":"Which layer the effective value comes from: `group`, `tenant`, or `default`. Groups have no account layer. See [Settings Hierarchy](https://docs.material.security/learn-more/administration/settings-hierarchy) for how the layers resolve.","type":"string","enum":["group","tenant","default"]}},"required":["enabled","source"]},"APIGroupModeSetting":{"title":"APIGroupModeSetting","type":"object","properties":{"mode":{"description":"How [Email Bomb Protection](https://docs.material.security/learn-more/risk-areas/email-threats/detect/material-email-threat-detections/email-bomb-protection) is applied to this group's members in this tenant: `enabled` (detect and remediate), `detection_only` (detect without remediating), or `disabled`.","type":"string","enum":["enabled","detection_only","disabled"]},"source":{"description":"Which layer the effective value comes from: `group`, `tenant`, or `default`. Groups have no account layer. See [Settings Hierarchy](https://docs.material.security/learn-more/administration/settings-hierarchy) for how the layers resolve.","type":"string","enum":["group","tenant","default"]}},"required":["mode","source"]},"APIGroupLicenses":{"title":"APIGroupLicenses","type":"object","properties":{"values":{"description":"The licenses this group allocates to its members: `essentials` (Essentials), `advanced` (Advanced), or `ato_resilience` (ATO Resilience). A group allocates at most one tier, `essentials` or `advanced`, and can add `ato_resilience` alongside it.","type":"array","items":{"type":"string","enum":["essentials","advanced","ato_resilience"]}},"source":{"description":"Which layer the effective value comes from: `group`, `tenant`, or `default`. Groups have no account layer. See [Settings Hierarchy](https://docs.material.security/learn-more/administration/settings-hierarchy) for how the layers resolve.","type":"string","enum":["group","tenant","default"]}},"required":["values","source"]},"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/groups/bulk":{"post":{"operationId":"bulkGroups","summary":"Bulk Groups","description":"Applies up to 200 group update operations in one request, best-effort with per-item results in request order (`results[i]` corresponds to `operations[i]`). A well-formed envelope always returns 200; individual failures are reported in `results[]`.","tags":["Groups"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkGroupsBody"}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkGroupsResponse"}}}},"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/groups.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.
