# Groups

A Group is a named set of Users, identified by its unique `group_id` or by its unique `name`.
Groups make access management scale: instead of assigning [Roles](/vertex/users_and_access_control#system-roles) and [Key Permissions](/vertex/users_and_access_control#key-ownership-and-permissions) to each User one by one, you assign them once to a Group and manage membership.

Groups affect their members in two ways:

1. **System Roles**: a Group carries a set of Roles. A User's effective Roles are the union of their own Roles and the Roles of every Group they belong to.
2. **Key Permissions**: a Group can be granted usage permissions on Keys. A User can use a Key if they hold the permission directly or through any Group they are a member of. See [Group-based Key Permissions](#group-based-key-permissions) below.

## Role Requirements

Group management endpoints are `SystemAdmin` operations. Read-only endpoints are also available to `ResourceViewer`:

| Endpoint | Method | Required Roles |
| --- | --- | --- |
| `/admin/groups/create` | `POST` | `SystemAdmin` |
| `/admin/groups/delete` | `DELETE` | `SystemAdmin` |
| `/admin/groups/add-members` | `POST` | `SystemAdmin` |
| `/admin/groups/remove-members` | `POST` | `SystemAdmin` |
| `/admin/groups/add-roles` | `POST` | `SystemAdmin` |
| `/admin/groups/remove-roles` | `POST` | `SystemAdmin` |
| `/admin/groups/list` | `GET` | `SystemAdmin`, `ResourceViewer` |
| `/admin/groups/describe` | `GET` | `SystemAdmin`, `ResourceViewer` |
| `/admin/groups/list-keys` | `GET` | `SystemAdmin`, `ResourceViewer` |
| `/admin/get-user-groups` | `GET` | `SystemAdmin`, `ResourceViewer` |

:::note[Backwards Compatibility]
All `/admin` endpoints remain accessible by the Admin Token set in the Vertex startup configuration in addition to Users with sufficient Roles.
:::

## Creating a Group

To create a Group, a `SystemAdmin` sends a POST request to the [`/admin/groups/create`](https://docs.sodot.dev/vertex-api-reference/#tag/admin/POST/admin/groups/create) endpoint with a unique `name` and the set of Roles the Group carries (`roles` is required; pass an empty array for a Group with no Roles):

```bash
curl -L -X POST 'https://<YOUR_VERTEX>/admin/groups/create' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: <ADMIN_TOKEN>' \
--data-raw '{
  "name": "prod-signers",
  "roles": ["crypto_user"]
}'
```

Role values are passed in their snake\_case form: `system_admin`, `policies_manager`, `resource_viewer`, `crypto_user`, `keys_manager`, `keys_importer`, `keys_exporter`, `keys_freezer`. See the full Roles table in [Users and Access Control](/vertex/users_and_access_control#system-roles).

In response you receive the new Group's `id` and `name`:

```json
{
  "id": "<GROUP_ID>",
  "name": "prod-signers"
}
```

Creating a Group with a `name` that already exists fails with a `409` `group_already_exists` error.

## Managing Group Members

### Adding Members

To add Users to a Group, send a POST request to the [`/admin/groups/add-members`](https://docs.sodot.dev/vertex-api-reference/#tag/admin/POST/admin/groups/add-members) endpoint.
The Group is identified by either `group_id` or `group_name` (exactly one of the two), and each member is identified by either `user_id` or `user_name`:

```bash
curl -L -X POST 'https://<YOUR_VERTEX>/admin/groups/add-members' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: <ADMIN_TOKEN>' \
--data-raw '{
  "group_name": "prod-signers",
  "members": [
    { "user_id": "<USER_ID>" },
    { "user_name": "<USER_NAME>" }
  ]
}'
```

A `200 OK` response indicates the members were added. If one of the supplied Users is already a member, the request fails with a `400` `user_already_in_group` error.

### Removing Members

To remove Users from a Group, send a POST request to the [`/admin/groups/remove-members`](https://docs.sodot.dev/vertex-api-reference/#tag/admin/POST/admin/groups/remove-members) endpoint with the same request body format:

```bash
curl -L -X POST 'https://<YOUR_VERTEX>/admin/groups/remove-members' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: <ADMIN_TOKEN>' \
--data-raw '{
  "group_name": "prod-signers",
  "members": [
    { "user_id": "<USER_ID>" }
  ]
}'
```

If one of the supplied Users is not a member of the Group, the request fails with a `400` `user_not_in_group` error.

## Managing Group Roles

A `SystemAdmin` can change the Roles a Group carries at any time. The change immediately affects the effective Roles of all its members.

To grant Roles, send a POST request to the [`/admin/groups/add-roles`](https://docs.sodot.dev/vertex-api-reference/#tag/admin/POST/admin/groups/add-roles) endpoint. The supplied Roles are added on top of the Group's existing Roles:

```bash
curl -L -X POST 'https://<YOUR_VERTEX>/admin/groups/add-roles' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: <ADMIN_TOKEN>' \
--data-raw '{
  "group_name": "prod-signers",
  "roles": ["keys_manager"]
}'
```

To remove Roles, send a POST request to the [`/admin/groups/remove-roles`](https://docs.sodot.dev/vertex-api-reference/#tag/admin/POST/admin/groups/remove-roles) endpoint with the same request body format.

:::note
Removing a Role from a Group does not affect Roles a member holds directly. A User that is a `CryptoUser` on their own keeps that Role even if it is removed from their Group.
:::

## Inspecting Groups

### Listing All Groups

To list all Groups in the system, send a GET request to the [`/admin/groups/list`](https://docs.sodot.dev/vertex-api-reference/#tag/admin/GET/admin/groups/list) endpoint. The optional `count` and `from` query parameters paginate the results (maximum number of Groups to return, and number of Groups to skip):

```bash
curl -L -X GET 'https://<YOUR_VERTEX>/admin/groups/list?count=10&from=0' \
-H 'Accept: application/json' \
-H 'Authorization: <ADMIN_TOKEN>'
```

The response is an array of Group descriptions, each including the Group's Roles and members:

```json
[
  {
    "id": "<GROUP_ID>",
    "name": "prod-signers",
    "roles": ["crypto_user"],
    "members": [
      {
        "id": "<USER_ID>",
        "name": "signing-machine-1",
        "roles": ["crypto_user"]
      }
    ]
  }
]
```

### Describing a Group

To fetch a single Group by its `group_id` or `group_name`, send a GET request to the [`/admin/groups/describe`](https://docs.sodot.dev/vertex-api-reference/#tag/admin/GET/admin/groups/describe) endpoint:

```bash
curl -L -X GET 'https://<YOUR_VERTEX>/admin/groups/describe?group_name=prod-signers' \
-H 'Accept: application/json' \
-H 'Authorization: <ADMIN_TOKEN>'
```

The response is a single Group description in the same format as above. If no such Group exists, the request fails with a `400` `group_not_found` error.

### Listing the Groups of a User

To list all Groups a specific User is a member of, send a GET request to the [`/admin/get-user-groups`](https://docs.sodot.dev/vertex-api-reference/#tag/admin/GET/admin/get-user-groups) endpoint, identifying the User by either `user_id` or `user_name`:

```bash
curl -L -X GET 'https://<YOUR_VERTEX>/admin/get-user-groups?user_name=signing-machine-1' \
-H 'Accept: application/json' \
-H 'Authorization: <ADMIN_TOKEN>'
```

The response is an array of the User's Groups, each with its `id`, `name` and `roles`.

### Listing Keys Assigned to a Group

To list all Keys a Group has usage permissions on, send a GET request to the [`/admin/groups/list-keys`](https://docs.sodot.dev/vertex-api-reference/#tag/admin/GET/admin/groups/list-keys) endpoint, identifying the Group by either `group_id` or `group_name`:

```bash
curl -L -X GET 'https://<YOUR_VERTEX>/admin/groups/list-keys?group_name=prod-signers' \
-H 'Accept: application/json' \
-H 'Authorization: <ADMIN_TOKEN>'
```

The response is an array of Key descriptions, including each Key's direct User permissions and Group permissions:

```json
[
  {
    "key_id": "<KEY_ID>",
    "key_type": "Ecdsa",
    "name": "treasury-key",
    "key_users": [
      { "user_id": "<USER_ID>", "usage_permission": "admin" }
    ],
    "key_groups": [
      { "group_id": "<GROUP_ID>", "group_name": "prod-signers", "usage_permission": "use" }
    ]
  }
]
```

## Group-based Key Permissions

The [`/admin/keys/grant-usage-permission`](https://docs.sodot.dev/vertex-api-reference/#tag/admin/POST/admin/keys/grant-usage-permission) and [`/admin/keys/revoke-usage-permission`](https://docs.sodot.dev/vertex-api-reference/#tag/admin/DELETE/admin/keys/revoke-usage-permission) endpoints described in [Users and Access Control](/vertex/users_and_access_control#key-ownership-and-permissions) accept a Group as the grantee: pass `group_id` or `group_name` instead of `user_id` or `user_name`.

Granting a Group the `use` permission on a Key lets every member of the Group `sign` and `derive-pubkey` with that Key:

```bash
curl -L -X POST 'https://<YOUR_VERTEX>/admin/keys/grant-usage-permission' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: <ADMIN_TOKEN>' \
--data-raw '{
  "key_id": "<KEY_ID>",
  "group_name": "prod-signers",
  "permission": "use"
}'
```

Revoking works the same way, with no `permission` field:

```bash
curl -L -X DELETE 'https://<YOUR_VERTEX>/admin/keys/revoke-usage-permission' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: <ADMIN_TOKEN>' \
--data-raw '{
  "key_id": "<KEY_ID>",
  "group_name": "prod-signers"
}'
```

:::note
As with User grants, these endpoints require the caller to be a `SystemAdmin`, or a `KeysManager` holding the `Admin` Key Permission for the specific Key. Roles are checked first, then Key Permissions, as described in [Users and Access Control](/vertex/users_and_access_control#roles-and-key-permission-enforcement).
:::

A typical setup grants a Group of production machines the `use` permission on signing Keys, while an operations Group holds the `admin` permission for lifecycle operations. Onboarding a new machine then only requires adding its User to the right Group.

## Deleting a Group

To delete a Group, send a DELETE request to the [`/admin/groups/delete`](https://docs.sodot.dev/vertex-api-reference/#tag/admin/DELETE/admin/groups/delete) endpoint, identifying the Group by either `group_id` or `group_name`:

```bash
curl -L -X DELETE 'https://<YOUR_VERTEX>/admin/groups/delete?group_name=prod-signers' \
-H 'Accept: application/json' \
-H 'Authorization: <ADMIN_TOKEN>'
```

Deleting a Group removes all of its memberships; the member Users themselves are not affected.

:::warning[Groups with Key Permissions Cannot Be Deleted]
The delete operation fails with a `400` `group_has_associated_keys` error if the Group still holds usage permissions on any Key. First list the Group's Keys using [`/admin/groups/list-keys`](https://docs.sodot.dev/vertex-api-reference/#tag/admin/GET/admin/groups/list-keys), revoke each permission using [`/admin/keys/revoke-usage-permission`](https://docs.sodot.dev/vertex-api-reference/#tag/admin/DELETE/admin/keys/revoke-usage-permission), and then delete the Group.
:::

For the full list of Group-related errors, see [Vertex Errors](/vertex/vertex_errors).
