Group service#

Service for managing groups within an organization

OpenAPI file: nominal.authentication.groups.v1.json

Endpoints#

Create or update group#

POST /authentication/groups/v1

Org-scoped upsert.

Creates a new group if Group.rid is empty in the request (server assigns the rid). Both Group.org_rid and Group.group_id are required on create, and the new group_id must be unique within the organization.

Updates an existing group if Group.rid is present in the request. Group.org_rid and Group.group_id are immutable: when set on the update request they must match the existing values, but they may be omitted to leave them unchanged. Fields in the group message marked as OUTPUT_ONLY are ignored when present in the input request. All other mutable fields are fully overwritten, and will be cleared if not set in the request.

Throws HTTP 400 / gRPC 3 if a supplied immutable field does not match the existing group. Throws HTTP 404 / gRPC 5 if the group identified by Group.rid for an update does not exist. Throws HTTP 409 / gRPC 6 if a create would result in duplicate group_ids within the organization. Throws HTTP 403 / gRPC 7 if the caller is not authorized.

Body

group Group required

​

Fields of Group
rid string

​

orgRid string

Required on create requests; immutable on updates.

groupId string

Group ID, unique per org. If sourced from the customer’s IdP, will match IdP group name. Required on create requests; immutable on updates.

displayName string

​

description string

​

userRids array of string output only

The list of users in this group.

createdAt string (date-time) output only

​

updatedAt string (date-time) output only

​

symbol Symbol

Symbol to identify groups

Fields of Symbol
one of icon, emoji, image required

​

icon string

Icon name (e.g. castle)

emoji string

Emoji name (e.g. :castle:)

image string

Image url (e.g. https://example.com/image.png)

membershipManagedManually boolean

Whether group membership is managed manually in Nominal. Defaults to false.

Response

rid string

​

orgRid string

Required on create requests; immutable on updates.

groupId string

Group ID, unique per org. If sourced from the customer’s IdP, will match IdP group name. Required on create requests; immutable on updates.

displayName string

​

description string

​

userRids array of string

The list of users in this group.

createdAt string (date-time)

​

updatedAt string (date-time)

​

symbol Symbol

Symbol to identify groups

Fields of Symbol
one of icon, emoji, image

​

icon string

Icon name (e.g. castle)

emoji string

Emoji name (e.g. :castle:)

image string

Image url (e.g. https://example.com/image.png)

membershipManagedManually boolean

Whether group membership is managed manually in Nominal. Defaults to false.

Request

curl -X POST "https://api.gov.nominal.io/api/authentication/groups/v1" \
  -H "Authorization: Bearer <api key>" \
  -H "Content-Type: application/json" \
  --data '{
  "group": {
    "rid": "<rid>",
    "orgRid": "<org rid>",
    "groupId": "<group id>",
    "displayName": "<display name>",
    "description": "<description>",
    "symbol": {
      "icon": "<icon>"
    },
    "membershipManagedManually": true
  }
}'
import requests

response = requests.post(
    "https://api.gov.nominal.io/api/authentication/groups/v1",
    headers={"Authorization": "Bearer <api key>"},
    json={
        "group": {
            "rid": "<rid>",
            "orgRid": "<org rid>",
            "groupId": "<group id>",
            "displayName": "<display name>",
            "description": "<description>",
            "symbol": {"icon": "<icon>"},
            "membershipManagedManually": True,
        },
    },
)
response.raise_for_status()
print(response.json())
import httpx

response = httpx.post(
    "https://api.gov.nominal.io/api/authentication/groups/v1",
    headers={"Authorization": "Bearer <api key>"},
    json={
        "group": {
            "rid": "<rid>",
            "orgRid": "<org rid>",
            "groupId": "<group id>",
            "displayName": "<display name>",
            "description": "<description>",
            "symbol": {"icon": "<icon>"},
            "membershipManagedManually": True,
        },
    },
)
response.raise_for_status()
print(response.json())
import asyncio

import aiohttp


async def main() -> None:
    async with aiohttp.ClientSession() as session:
        async with session.post(
            "https://api.gov.nominal.io/api/authentication/groups/v1",
            headers={"Authorization": "Bearer <api key>"},
            json={
                "group": {
                    "rid": "<rid>",
                    "orgRid": "<org rid>",
                    "groupId": "<group id>",
                    "displayName": "<display name>",
                    "description": "<description>",
                    "symbol": {"icon": "<icon>"},
                    "membershipManagedManually": True,
                },
            },
        ) as response:
            response.raise_for_status()
            print(await response.json())


asyncio.run(main())

Response: 200

{
  "rid": "<rid>",
  "orgRid": "<org rid>",
  "groupId": "<group id>",
  "displayName": "<display name>",
  "description": "<description>",
  "userRids": [
    "<user rids>"
  ],
  "createdAt": "2026-01-01T00:00:00Z",
  "updatedAt": "2026-01-01T00:00:00Z",
  "symbol": {
    "icon": "<icon>"
  },
  "membershipManagedManually": true
}

Get groups#

POST /authentication/groups/v1/batch-get

Get batch of groups within the user’s organization

Body

The body is an array of string.

Response

The body is a map of string to Group.

Fields of Group
rid string

​

orgRid string

Required on create requests; immutable on updates.

groupId string

Group ID, unique per org. If sourced from the customer’s IdP, will match IdP group name. Required on create requests; immutable on updates.

displayName string

​

description string

​

userRids array of string

The list of users in this group.

createdAt string (date-time)

​

updatedAt string (date-time)

​

symbol Symbol

Symbol to identify groups

Fields of Symbol
one of icon, emoji, image

​

icon string

Icon name (e.g. castle)

emoji string

Emoji name (e.g. :castle:)

image string

Image url (e.g. https://example.com/image.png)

membershipManagedManually boolean

Whether group membership is managed manually in Nominal. Defaults to false.

Request

curl -X POST "https://api.gov.nominal.io/api/authentication/groups/v1/batch-get" \
  -H "Authorization: Bearer <api key>" \
  -H "Content-Type: application/json" \
  --data '[
  "string"
]'
import requests

response = requests.post(
    "https://api.gov.nominal.io/api/authentication/groups/v1/batch-get",
    headers={"Authorization": "Bearer <api key>"},
    json=["string"],
)
response.raise_for_status()
print(response.json())
import httpx

response = httpx.post(
    "https://api.gov.nominal.io/api/authentication/groups/v1/batch-get",
    headers={"Authorization": "Bearer <api key>"},
    json=["string"],
)
response.raise_for_status()
print(response.json())
import asyncio

import aiohttp


async def main() -> None:
    async with aiohttp.ClientSession() as session:
        async with session.post(
            "https://api.gov.nominal.io/api/authentication/groups/v1/batch-get",
            headers={"Authorization": "Bearer <api key>"},
            json=["string"],
        ) as response:
            response.raise_for_status()
            print(await response.json())


asyncio.run(main())

Response: 200

{
  "<key>": {
    "rid": "<rid>",
    "orgRid": "<org rid>",
    "groupId": "<group id>",
    "displayName": "<display name>",
    "description": "<description>",
    "userRids": [
      "<user rids>"
    ],
    "createdAt": "2026-01-01T00:00:00Z",
    "updatedAt": "2026-01-01T00:00:00Z",
    "symbol": {
      "icon": "<icon>"
    },
    "membershipManagedManually": true
  }
}

Get group by ID#

GET /authentication/groups/v1/id/{groupId}

Gets a group by its ID within the user’s organization

Path parameters

groupId string required

​

Response

rid string

​

orgRid string

Required on create requests; immutable on updates.

groupId string

Group ID, unique per org. If sourced from the customer’s IdP, will match IdP group name. Required on create requests; immutable on updates.

displayName string

​

description string

​

userRids array of string

The list of users in this group.

createdAt string (date-time)

​

updatedAt string (date-time)

​

symbol Symbol

Symbol to identify groups

Fields of Symbol
one of icon, emoji, image

​

icon string

Icon name (e.g. castle)

emoji string

Emoji name (e.g. :castle:)

image string

Image url (e.g. https://example.com/image.png)

membershipManagedManually boolean

Whether group membership is managed manually in Nominal. Defaults to false.

Request

curl "https://api.gov.nominal.io/api/authentication/groups/v1/id/<group id>" \
  -H "Authorization: Bearer <api key>"
import requests

response = requests.get(
    "https://api.gov.nominal.io/api/authentication/groups/v1/id/<group id>",
    headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import httpx

response = httpx.get(
    "https://api.gov.nominal.io/api/authentication/groups/v1/id/<group id>",
    headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import asyncio

import aiohttp


async def main() -> None:
    async with aiohttp.ClientSession() as session:
        async with session.get(
            "https://api.gov.nominal.io/api/authentication/groups/v1/id/<group id>",
            headers={"Authorization": "Bearer <api key>"},
        ) as response:
            response.raise_for_status()
            print(await response.json())


asyncio.run(main())

Response: 200

{
  "rid": "<rid>",
  "orgRid": "<org rid>",
  "groupId": "<group id>",
  "displayName": "<display name>",
  "description": "<description>",
  "userRids": [
    "<user rids>"
  ],
  "createdAt": "2026-01-01T00:00:00Z",
  "updatedAt": "2026-01-01T00:00:00Z",
  "symbol": {
    "icon": "<icon>"
  },
  "membershipManagedManually": true
}

Search groups#

POST /authentication/groups/v1/search

Searches all groups in the user’s organization using given query

Body

pageSize integer

Page sizes greater than 1_000 will be rejected. Default pageSize is 100.

nextPageToken string

​

query SearchGroupsQuery required

​

Fields of SearchGroupsQuery
one of exactSubstringText, and, or, memberUsers

​

exactSubstringText string

​

and SearchQueryAnd

and is implemented to allow for list (use SearchQueryAnd([]))

Fields of SearchQueryAnd
queries array of SearchGroupsQuery

​

or SearchQueryOr

​

Fields of SearchQueryOr
queries array of SearchGroupsQuery

​

memberUsers SearchQueryMemberUsers

​

Fields of SearchQueryMemberUsers
userRids array of string

1 to 1,000 items. Each item: at most 256 characters.

Response

results array of Group

​

Fields of Group
rid string

​

orgRid string

Required on create requests; immutable on updates.

groupId string

Group ID, unique per org. If sourced from the customer’s IdP, will match IdP group name. Required on create requests; immutable on updates.

displayName string

​

description string

​

userRids array of string

The list of users in this group.

createdAt string (date-time)

​

updatedAt string (date-time)

​

symbol Symbol

Symbol to identify groups

Fields of Symbol
one of icon, emoji, image

​

icon string

Icon name (e.g. castle)

emoji string

Emoji name (e.g. :castle:)

image string

Image url (e.g. https://example.com/image.png)

membershipManagedManually boolean

Whether group membership is managed manually in Nominal. Defaults to false.

nextPageToken string

​

Request

curl -X POST "https://api.gov.nominal.io/api/authentication/groups/v1/search" \
  -H "Authorization: Bearer <api key>" \
  -H "Content-Type: application/json" \
  --data '{
  "query": {
    "exactSubstringText": "<exact substring text>"
  }
}'
import requests

response = requests.post(
    "https://api.gov.nominal.io/api/authentication/groups/v1/search",
    headers={"Authorization": "Bearer <api key>"},
    json={"query": {"exactSubstringText": "<exact substring text>"}},
)
response.raise_for_status()
print(response.json())
import httpx

response = httpx.post(
    "https://api.gov.nominal.io/api/authentication/groups/v1/search",
    headers={"Authorization": "Bearer <api key>"},
    json={"query": {"exactSubstringText": "<exact substring text>"}},
)
response.raise_for_status()
print(response.json())
import asyncio

import aiohttp


async def main() -> None:
    async with aiohttp.ClientSession() as session:
        async with session.post(
            "https://api.gov.nominal.io/api/authentication/groups/v1/search",
            headers={"Authorization": "Bearer <api key>"},
            json={"query": {"exactSubstringText": "<exact substring text>"}},
        ) as response:
            response.raise_for_status()
            print(await response.json())


asyncio.run(main())

Response: 200

{
  "results": [
    {
      "rid": "<rid>",
      "orgRid": "<org rid>",
      "groupId": "<group id>",
      "displayName": "<display name>",
      "description": "<description>",
      "userRids": [
        "<user rids>"
      ],
      "createdAt": "2026-01-01T00:00:00Z",
      "updatedAt": "2026-01-01T00:00:00Z",
      "symbol": {
        "icon": "<icon>"
      },
      "membershipManagedManually": true
    }
  ],
  "nextPageToken": "<next page token>"
}

Create group membership#

POST /authentication/groups/v1/{groupMembership.key.groupRid}/memberships

Adds a member to a manually managed group. Re-adding an existing member is a no-op. Throws HTTP 400 / gRPC 3 if group_rid or member_rid is missing, or member_rid is not a supported RID type. Throws HTTP 403 / gRPC 7 if the caller is not authorized to update the group, including when the group does not exist. The permission check runs before the group lookup so unknown groups are not disclosed. Throws HTTP 400 / gRPC 3 if the target user is not in the group’s organization. Throws HTTP 400 / gRPC 3 if the group’s membership is not managed manually.

Path parameters

groupMembership.key.groupRid string required

At most 256 characters.

Body

key object

Identity is a nested key so delete can address a membership without the full resource, which may gain fields later. Identity is a nested key so delete can address a membership without the full resource, which may gain fields later.

Response

key GroupMembershipKey

Identity is a nested key so delete can address a membership without the full resource, which may gain fields later.

Fields of GroupMembershipKey
groupRid string

At most 256 characters.

memberRid string

The member of the group. Only user RIDs are accepted today. At most 256 characters.

Request

curl -X POST "https://api.gov.nominal.io/api/authentication/groups/v1/<group membership.key.group rid>/memberships" \
  -H "Authorization: Bearer <api key>" \
  -H "Content-Type: application/json" \
  --data '{
  "key": {
    "memberRid": "<member rid>"
  }
}'
import requests

response = requests.post(
    "https://api.gov.nominal.io/api/authentication/groups/v1/<group membership.key.group rid>/memberships",
    headers={"Authorization": "Bearer <api key>"},
    json={"key": {"memberRid": "<member rid>"}},
)
response.raise_for_status()
print(response.json())
import httpx

response = httpx.post(
    "https://api.gov.nominal.io/api/authentication/groups/v1/<group membership.key.group rid>/memberships",
    headers={"Authorization": "Bearer <api key>"},
    json={"key": {"memberRid": "<member rid>"}},
)
response.raise_for_status()
print(response.json())
import asyncio

import aiohttp


async def main() -> None:
    async with aiohttp.ClientSession() as session:
        async with session.post(
            "https://api.gov.nominal.io/api/authentication/groups/v1/<group membership.key.group rid>/memberships",
            headers={"Authorization": "Bearer <api key>"},
            json={"key": {"memberRid": "<member rid>"}},
        ) as response:
            response.raise_for_status()
            print(await response.json())


asyncio.run(main())

Response: 200

{
  "key": {
    "groupRid": "<group rid>",
    "memberRid": "<member rid>"
  }
}

Get group#

GET /authentication/groups/v1/{groupRid}

Get group within the user’s organization

Path parameters

groupRid string required

​

Response

rid string

​

orgRid string

Required on create requests; immutable on updates.

groupId string

Group ID, unique per org. If sourced from the customer’s IdP, will match IdP group name. Required on create requests; immutable on updates.

displayName string

​

description string

​

userRids array of string

The list of users in this group.

createdAt string (date-time)

​

updatedAt string (date-time)

​

symbol Symbol

Symbol to identify groups

Fields of Symbol
one of icon, emoji, image

​

icon string

Icon name (e.g. castle)

emoji string

Emoji name (e.g. :castle:)

image string

Image url (e.g. https://example.com/image.png)

membershipManagedManually boolean

Whether group membership is managed manually in Nominal. Defaults to false.

Request

curl "https://api.gov.nominal.io/api/authentication/groups/v1/<group rid>" \
  -H "Authorization: Bearer <api key>"
import requests

response = requests.get(
    "https://api.gov.nominal.io/api/authentication/groups/v1/<group rid>",
    headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import httpx

response = httpx.get(
    "https://api.gov.nominal.io/api/authentication/groups/v1/<group rid>",
    headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import asyncio

import aiohttp


async def main() -> None:
    async with aiohttp.ClientSession() as session:
        async with session.get(
            "https://api.gov.nominal.io/api/authentication/groups/v1/<group rid>",
            headers={"Authorization": "Bearer <api key>"},
        ) as response:
            response.raise_for_status()
            print(await response.json())


asyncio.run(main())

Response: 200

{
  "rid": "<rid>",
  "orgRid": "<org rid>",
  "groupId": "<group id>",
  "displayName": "<display name>",
  "description": "<description>",
  "userRids": [
    "<user rids>"
  ],
  "createdAt": "2026-01-01T00:00:00Z",
  "updatedAt": "2026-01-01T00:00:00Z",
  "symbol": {
    "icon": "<icon>"
  },
  "membershipManagedManually": true
}

Update group metadata#

PUT /authentication/groups/v1/{groupRid}/metadata

Updates the metadata of a group

Path parameters

groupRid string required

​

Body

displayName string

​

description string

​

symbol UpdateGroupSymbolWrapper

​

Fields of UpdateGroupSymbolWrapper
value Symbol

​

Fields of Symbol
one of icon, emoji, image required

​

icon string

Icon name (e.g. castle)

emoji string

Emoji name (e.g. :castle:)

image string

Image url (e.g. https://example.com/image.png)

Response

rid string

​

orgRid string

Required on create requests; immutable on updates.

groupId string

Group ID, unique per org. If sourced from the customer’s IdP, will match IdP group name. Required on create requests; immutable on updates.

displayName string

​

description string

​

userRids array of string

The list of users in this group.

createdAt string (date-time)

​

updatedAt string (date-time)

​

symbol Symbol

Symbol to identify groups

Fields of Symbol
one of icon, emoji, image

​

icon string

Icon name (e.g. castle)

emoji string

Emoji name (e.g. :castle:)

image string

Image url (e.g. https://example.com/image.png)

membershipManagedManually boolean

Whether group membership is managed manually in Nominal. Defaults to false.

Request

curl -X PUT "https://api.gov.nominal.io/api/authentication/groups/v1/<group rid>/metadata" \
  -H "Authorization: Bearer <api key>" \
  -H "Content-Type: application/json" \
  --data '{
  "displayName": "<display name>",
  "description": "<description>",
  "symbol": {
    "value": {
      "icon": "<icon>"
    }
  }
}'
import requests

response = requests.put(
    "https://api.gov.nominal.io/api/authentication/groups/v1/<group rid>/metadata",
    headers={"Authorization": "Bearer <api key>"},
    json={
        "displayName": "<display name>",
        "description": "<description>",
        "symbol": {"value": {"icon": "<icon>"}},
    },
)
response.raise_for_status()
print(response.json())
import httpx

response = httpx.put(
    "https://api.gov.nominal.io/api/authentication/groups/v1/<group rid>/metadata",
    headers={"Authorization": "Bearer <api key>"},
    json={
        "displayName": "<display name>",
        "description": "<description>",
        "symbol": {"value": {"icon": "<icon>"}},
    },
)
response.raise_for_status()
print(response.json())
import asyncio

import aiohttp


async def main() -> None:
    async with aiohttp.ClientSession() as session:
        async with session.put(
            "https://api.gov.nominal.io/api/authentication/groups/v1/<group rid>/metadata",
            headers={"Authorization": "Bearer <api key>"},
            json={
                "displayName": "<display name>",
                "description": "<description>",
                "symbol": {"value": {"icon": "<icon>"}},
            },
        ) as response:
            response.raise_for_status()
            print(await response.json())


asyncio.run(main())

Response: 200

{
  "rid": "<rid>",
  "orgRid": "<org rid>",
  "groupId": "<group id>",
  "displayName": "<display name>",
  "description": "<description>",
  "userRids": [
    "<user rids>"
  ],
  "createdAt": "2026-01-01T00:00:00Z",
  "updatedAt": "2026-01-01T00:00:00Z",
  "symbol": {
    "icon": "<icon>"
  },
  "membershipManagedManually": true
}

Delete group membership#

DELETE /authentication/groups/v1/{key.groupRid}/memberships/{key.memberRid}

Removes a member from a manually managed group. Removing a non-member is a no-op. Throws HTTP 400 / gRPC 3 if group_rid or member_rid is missing, or member_rid is not a supported RID type. Throws HTTP 403 / gRPC 7 if the caller is not authorized to update the group, including when the group does not exist. The permission check runs before the group lookup so unknown groups are not disclosed. Throws HTTP 400 / gRPC 3 if the group’s membership is not managed manually.

Path parameters

key.groupRid string required

At most 256 characters.

key.memberRid string required

The member of the group. Only user RIDs are accepted today. At most 256 characters.

Response

An empty JSON object, {}.

Request

curl -X DELETE "https://api.gov.nominal.io/api/authentication/groups/v1/<key.group rid>/memberships/<key.member rid>" \
  -H "Authorization: Bearer <api key>"
import requests

response = requests.delete(
    "https://api.gov.nominal.io/api/authentication/groups/v1/<key.group rid>/memberships/<key.member rid>",
    headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import httpx

response = httpx.delete(
    "https://api.gov.nominal.io/api/authentication/groups/v1/<key.group rid>/memberships/<key.member rid>",
    headers={"Authorization": "Bearer <api key>"},
)
response.raise_for_status()
print(response.json())
import asyncio

import aiohttp


async def main() -> None:
    async with aiohttp.ClientSession() as session:
        async with session.delete(
            "https://api.gov.nominal.io/api/authentication/groups/v1/<key.group rid>/memberships/<key.member rid>",
            headers={"Authorization": "Bearer <api key>"},
        ) as response:
            response.raise_for_status()
            print(await response.json())


asyncio.run(main())

Response: 200

{}

Errors#

Errors shows how these errors are sent.

Each error’s errorName is NominalAuthenticationGroupsV1: followed by its name below.

Status

Name

Notes

400

GroupErrorsIdentityMismatch

Request identity field does not match the existing group

400

GroupErrorsInvalidRid

RID field is invalid

400

GroupErrorsMembershipNotManagedManually

Group membership is not managed manually

400

GroupErrorsMissingRequiredField

Required field missing on request

400

GroupErrorsRequestedPageSizeTooLarge

Requested page size is too large

400

GroupErrorsUserNotInOrg

User is not a member of the group organization

403

GroupErrorsUnauthorized

Not authorized for group

404

GroupErrorsNotFound

Group not found

409

GroupErrorsIdConflict

Group with given group_id already exists in organization

Types#

Group#

A group represents a collection of users within an organization

rid string

​

orgRid string

Required on create requests; immutable on updates.

groupId string

Group ID, unique per org. If sourced from the customer’s IdP, will match IdP group name. Required on create requests; immutable on updates.

displayName string

​

description string

​

userRids array of string output only

The list of users in this group.

createdAt string (date-time) output only

​

updatedAt string (date-time) output only

​

symbol Symbol

Symbol to identify groups

membershipManagedManually boolean

Whether group membership is managed manually in Nominal. Defaults to false.

GroupMembershipKey#

Client-known identity of a group membership.

groupRid string required

At most 256 characters.

memberRid string required

The member of the group. Only user RIDs are accepted today. At most 256 characters.

SearchGroupsQuery#

Set at most one of the fields below.

one of exactSubstringText, and, or, memberUsers

​

exactSubstringText string

​

and SearchQueryAnd

and is implemented to allow for list (use SearchQueryAnd([]))

memberUsers SearchQueryMemberUsers

​

SearchQueryAnd#

queries array of SearchGroupsQuery

​

SearchQueryMemberUsers#

Matches the groups that any of the users is a direct member of, whether that membership is synced from the identity provider or managed manually.

userRids array of string

1 to 1,000 items. Each item: at most 256 characters.

SearchQueryOr#

queries array of SearchGroupsQuery

​

Symbol#

Set exactly one of the fields below.

one of icon, emoji, image required

​

icon string

Icon name (e.g. castle)

emoji string

Emoji name (e.g. :castle:)

image string

Image url (e.g. https://example.com/image.png)

UpdateGroupSymbolWrapper#

value Symbol

​

Page design based on Scalar, MIT License.