# Groups

## List

`zones.groups.list(strzone_id, GroupListParams**kwargs)  -> GroupListResponse`

**get** `/zones/{zoneId}/groups`

Returns a paginated list of the groups in the specified zone. Use cursor pagination via `after`/`before`. Sort: comma-separated field list; prefix with `-` for descending (allowed: created_at, name, identifier). Pass `expand[]=member_count` to include each group's member count, `expand[]=roles` to include the identifiers of the roles assigned to each group, and `expand[]=total_count` to include the matching row count. Filter by exact identifier via `filter[identifier]` (repeatable, OR'd across values). Search via `query[]` (case-insensitive substring match, OR'd across repeated values); it matches the group's name and identifier. Pass `filter[id]` (repeatable, max 100) to restrict results to a known set of groups — mutually exclusive with `after`/`before` (returns 400 if combined). When `filter[id]` is set, `limit` is ignored and the response contains every requested group that exists in the zone, in a single page. IDs not in the zone are silently omitted.

### Parameters

- `zone_id: str`

- `after: Optional[str]`

  Cursor for forward pagination

- `before: Optional[str]`

  Cursor for backward pagination

- `expand: Optional[Union[Literal["total_count", "member_count", "roles"], List[Literal["total_count", "member_count", "roles"]]]]`

  - `Literal["total_count", "member_count", "roles"]`

    - `"total_count"`

    - `"member_count"`

    - `"roles"`

  - `List[Literal["total_count", "member_count", "roles"]]`

    - `"total_count"`

    - `"member_count"`

    - `"roles"`

- `filter_id: Optional[Union[str, SequenceNotStr[str]]]`

  Restrict results to groups with this ID. Repeatable, max 100. Mutually exclusive with after/before.

  - `str`

    Restrict results to groups with this ID. Repeatable, max 100. Mutually exclusive with after/before.

  - `SequenceNotStr[str]`

- `filter_identifier: Optional[Union[str, SequenceNotStr[str]]]`

  Filter by exact group identifier

  - `str`

    Filter by exact group identifier

  - `SequenceNotStr[str]`

- `limit: Optional[int]`

  Maximum number of items to return

- `query: Optional[Union[str, SequenceNotStr[str]]]`

  Search across name and identifier (substring match)

  - `str`

    Search across name and identifier (substring match)

  - `SequenceNotStr[str]`

- `sort: Optional[str]`

  Comma-separated sort fields. Prefix with - for descending. Allowed: created_at, name, identifier

### Returns

- `class GroupListResponse: …`

  - `items: List[Group]`

    - `id: str`

      Unique identifier of the group

    - `created_at: datetime`

      Entity creation timestamp

    - `external: bool`

      Whether the group is synced from an external directory. When true the group is directory-owned and its membership is read-only; when false it is managed in Keycard. Read-only: set by external sync, never by the caller.

    - `identifier: str`

      User-specified identifier, unique within the zone. Automatically assigned for groups from an external directory.

    - `name: str`

      Human-readable group name

    - `organization_id: str`

      Organization this group belongs to

    - `updated_at: datetime`

      Entity update timestamp

    - `zone_id: str`

      Zone this group belongs to

    - `member_count: Optional[int]`

      Number of users in the group. Included only when requested via `expand[]=member_count` (group get or list).

    - `roles: Optional[List[str]]`

      Identifiers of the roles assigned to the group; members inherit them. Deduped across scopes. Included only when requested via `expand[]=roles` (group get or list).

  - `pagination: Pagination`

    Cursor-based pagination metadata

    - `after_cursor: Optional[str]`

      An opaque cursor used for paginating through a list of results

    - `before_cursor: Optional[str]`

      An opaque cursor used for paginating through a list of results

    - `total_count: Optional[int]`

      Total number of items matching the query. Only included when expand[]=total_count is requested.

### Example

```python
import os
from keycardai_api import KeycardAPI

client = KeycardAPI(
    api_key=os.environ.get("KEYCARD_API_API_KEY"),  # This is the default and can be omitted
)
groups = client.zones.groups.list(
    zone_id="zoneId",
)
print(groups.items)
```

## Create

`zones.groups.create(strzone_id, GroupCreateParams**kwargs)  -> Group`

**post** `/zones/{zoneId}/groups`

Creates a group in the zone (managed in Keycard). Groups synced from an external directory are created by that directory, not here.

### Parameters

- `zone_id: str`

- `name: str`

  Human-readable group name

- `identifier: Optional[str]`

  User-specified identifier, unique within the zone. Derived from the name when omitted (a suffix is appended if it collides).

### Returns

- `class Group: …`

  A zone-scoped group of users, assignable to roles and usable in policies. Roles assigned to a group are inherited by its members. `external` is false for groups managed in Keycard and true for groups synced from an external directory.

  - `id: str`

    Unique identifier of the group

  - `created_at: datetime`

    Entity creation timestamp

  - `external: bool`

    Whether the group is synced from an external directory. When true the group is directory-owned and its membership is read-only; when false it is managed in Keycard. Read-only: set by external sync, never by the caller.

  - `identifier: str`

    User-specified identifier, unique within the zone. Automatically assigned for groups from an external directory.

  - `name: str`

    Human-readable group name

  - `organization_id: str`

    Organization this group belongs to

  - `updated_at: datetime`

    Entity update timestamp

  - `zone_id: str`

    Zone this group belongs to

  - `member_count: Optional[int]`

    Number of users in the group. Included only when requested via `expand[]=member_count` (group get or list).

  - `roles: Optional[List[str]]`

    Identifiers of the roles assigned to the group; members inherit them. Deduped across scopes. Included only when requested via `expand[]=roles` (group get or list).

### Example

```python
import os
from keycardai_api import KeycardAPI

client = KeycardAPI(
    api_key=os.environ.get("KEYCARD_API_API_KEY"),  # This is the default and can be omitted
)
group = client.zones.groups.create(
    zone_id="zoneId",
    name="x",
)
print(group.id)
```

## Retrieve

`zones.groups.retrieve(strgroup_id, GroupRetrieveParams**kwargs)  -> Group`

**get** `/zones/{zoneId}/groups/{groupId}`

Returns a group by ID. Pass `expand[]=member_count` for its member count and `expand[]=roles` for the identifiers of its assigned roles.

### Parameters

- `zone_id: str`

- `group_id: str`

- `expand: Optional[Union[Literal["member_count", "roles"], List[Literal["member_count", "roles"]]]]`

  - `Literal["member_count", "roles"]`

    - `"member_count"`

    - `"roles"`

  - `List[Literal["member_count", "roles"]]`

    - `"member_count"`

    - `"roles"`

### Returns

- `class Group: …`

  A zone-scoped group of users, assignable to roles and usable in policies. Roles assigned to a group are inherited by its members. `external` is false for groups managed in Keycard and true for groups synced from an external directory.

  - `id: str`

    Unique identifier of the group

  - `created_at: datetime`

    Entity creation timestamp

  - `external: bool`

    Whether the group is synced from an external directory. When true the group is directory-owned and its membership is read-only; when false it is managed in Keycard. Read-only: set by external sync, never by the caller.

  - `identifier: str`

    User-specified identifier, unique within the zone. Automatically assigned for groups from an external directory.

  - `name: str`

    Human-readable group name

  - `organization_id: str`

    Organization this group belongs to

  - `updated_at: datetime`

    Entity update timestamp

  - `zone_id: str`

    Zone this group belongs to

  - `member_count: Optional[int]`

    Number of users in the group. Included only when requested via `expand[]=member_count` (group get or list).

  - `roles: Optional[List[str]]`

    Identifiers of the roles assigned to the group; members inherit them. Deduped across scopes. Included only when requested via `expand[]=roles` (group get or list).

### Example

```python
import os
from keycardai_api import KeycardAPI

client = KeycardAPI(
    api_key=os.environ.get("KEYCARD_API_API_KEY"),  # This is the default and can be omitted
)
group = client.zones.groups.retrieve(
    group_id="groupId",
    zone_id="zoneId",
)
print(group.id)
```

## Update

`zones.groups.update(strgroup_id, GroupUpdateParams**kwargs)  -> Group`

**patch** `/zones/{zoneId}/groups/{groupId}`

Updates a group's name and/or identifier (partial update). A group's source is immutable. The name of a group synced from an external directory cannot be changed while external sync is enabled for the zone; its identifier can.

### Parameters

- `zone_id: str`

- `group_id: str`

- `identifier: Optional[str]`

  User-specified identifier, unique within the zone.

- `name: Optional[str]`

  Human-readable group name

### Returns

- `class Group: …`

  A zone-scoped group of users, assignable to roles and usable in policies. Roles assigned to a group are inherited by its members. `external` is false for groups managed in Keycard and true for groups synced from an external directory.

  - `id: str`

    Unique identifier of the group

  - `created_at: datetime`

    Entity creation timestamp

  - `external: bool`

    Whether the group is synced from an external directory. When true the group is directory-owned and its membership is read-only; when false it is managed in Keycard. Read-only: set by external sync, never by the caller.

  - `identifier: str`

    User-specified identifier, unique within the zone. Automatically assigned for groups from an external directory.

  - `name: str`

    Human-readable group name

  - `organization_id: str`

    Organization this group belongs to

  - `updated_at: datetime`

    Entity update timestamp

  - `zone_id: str`

    Zone this group belongs to

  - `member_count: Optional[int]`

    Number of users in the group. Included only when requested via `expand[]=member_count` (group get or list).

  - `roles: Optional[List[str]]`

    Identifiers of the roles assigned to the group; members inherit them. Deduped across scopes. Included only when requested via `expand[]=roles` (group get or list).

### Example

```python
import os
from keycardai_api import KeycardAPI

client = KeycardAPI(
    api_key=os.environ.get("KEYCARD_API_API_KEY"),  # This is the default and can be omitted
)
group = client.zones.groups.update(
    group_id="groupId",
    zone_id="zoneId",
)
print(group.id)
```

## Delete

`zones.groups.delete(strgroup_id, GroupDeleteParams**kwargs)`

**delete** `/zones/{zoneId}/groups/{groupId}`

Deletes a group and its memberships and role assignments. Groups synced from an external directory can only be deleted by that directory (after external sync is disabled).

### Parameters

- `zone_id: str`

- `group_id: str`

### Example

```python
import os
from keycardai_api import KeycardAPI

client = KeycardAPI(
    api_key=os.environ.get("KEYCARD_API_API_KEY"),  # This is the default and can be omitted
)
client.zones.groups.delete(
    group_id="groupId",
    zone_id="zoneId",
)
```

## Domain Types

### Group

- `class Group: …`

  A zone-scoped group of users, assignable to roles and usable in policies. Roles assigned to a group are inherited by its members. `external` is false for groups managed in Keycard and true for groups synced from an external directory.

  - `id: str`

    Unique identifier of the group

  - `created_at: datetime`

    Entity creation timestamp

  - `external: bool`

    Whether the group is synced from an external directory. When true the group is directory-owned and its membership is read-only; when false it is managed in Keycard. Read-only: set by external sync, never by the caller.

  - `identifier: str`

    User-specified identifier, unique within the zone. Automatically assigned for groups from an external directory.

  - `name: str`

    Human-readable group name

  - `organization_id: str`

    Organization this group belongs to

  - `updated_at: datetime`

    Entity update timestamp

  - `zone_id: str`

    Zone this group belongs to

  - `member_count: Optional[int]`

    Number of users in the group. Included only when requested via `expand[]=member_count` (group get or list).

  - `roles: Optional[List[str]]`

    Identifiers of the roles assigned to the group; members inherit them. Deduped across scopes. Included only when requested via `expand[]=roles` (group get or list).

### Group Create

- `class GroupCreate: …`

  Schema for creating a group in Keycard. Groups synced from an external directory are created by that directory, not through this endpoint.

  - `name: str`

    Human-readable group name

  - `identifier: Optional[str]`

    User-specified identifier, unique within the zone. Derived from the name when omitted (a suffix is appended if it collides).

### Group Update

- `class GroupUpdate: …`

  Schema for updating a group.

  - `identifier: Optional[str]`

    User-specified identifier, unique within the zone.

  - `name: Optional[str]`

    Human-readable group name

# Members

## List

`zones.groups.members.list(strgroup_id, MemberListParams**kwargs)  -> MemberListResponse`

**get** `/zones/{zoneId}/groups/{groupId}/members`

Returns a paginated list of the group's members. Use cursor pagination via `after`/`before`. Pass `expand[]=user` to embed each member's full user record and `expand[]=total_count` to include the matching row count. Pass `query[]` (repeatable, 1-255 chars) to search members by their user's email or federated credential subject (substring match, OR'd across repeated values). Pass `filter[id]` (repeatable, max 100) to restrict results to a known set of members by user ID — mutually exclusive with `after`/`before` (returns 400 if combined). When `filter[id]` is set, `limit` is ignored and the response contains every requested member that exists in the group, in a single page. IDs not in the group are silently omitted.

### Parameters

- `zone_id: str`

- `group_id: str`

- `after: Optional[str]`

  Cursor for forward pagination

- `before: Optional[str]`

  Cursor for backward pagination

- `expand: Optional[Union[Literal["total_count", "user"], List[Literal["total_count", "user"]]]]`

  - `Literal["total_count", "user"]`

    - `"total_count"`

    - `"user"`

  - `List[Literal["total_count", "user"]]`

    - `"total_count"`

    - `"user"`

- `filter_id: Optional[Union[str, SequenceNotStr[str]]]`

  Restrict results to the member with this user ID. Repeatable, max 100. Mutually exclusive with after/before.

  - `str`

    Restrict results to the member with this user ID. Repeatable, max 100. Mutually exclusive with after/before.

  - `SequenceNotStr[str]`

- `limit: Optional[int]`

  Maximum number of items to return

- `query: Optional[Union[str, SequenceNotStr[str]]]`

  Search members by their user's email or federated credential subject (substring match)

  - `str`

    Search members by their user's email or federated credential subject (substring match)

  - `SequenceNotStr[str]`

### Returns

- `class MemberListResponse: …`

  - `items: List[GroupMember]`

    - `created_at: datetime`

      Entity creation timestamp

    - `user_id: str`

      ID of the user

    - `user: Optional[User]`

      An authenticated user entity

      - `id: str`

        Unique identifier of the user

      - `created_at: datetime`

        Entity creation timestamp

      - `email: str`

        Email address of the user

      - `email_verified: bool`

        Whether the email address has been verified

      - `identifier: str`

        Zone-scoped user identifier. Defaults to the user's Keycard ID. When the provider has user_identifier_claim configured, the value is set from that claim at user creation time.

      - `organization_id: str`

        Organization that owns this user

      - `status: Literal["active", "disabled"]`

        Status of the user. Disabled users cannot authenticate.

        - `"active"`

        - `"disabled"`

      - `updated_at: datetime`

        Entity update timestamp

      - `zone_id: str`

        Zone this user belongs to

      - `authenticated_at: Optional[str]`

        Date when the user was last authenticated

      - `credentials: Optional[List[Credential]]`

        Authentication credentials for this user, each carrying its identity provider for federation credentials. Populated only when `expand[]=credentials` is set on the listing endpoint.

        - `class CredentialIamUserCredentialFederation: …`

          Federation credential: the user authenticates through an identity provider.

          - `created_at: datetime`

            Entity creation timestamp

          - `provider_id: Optional[str]`

            ID of the identity provider backing this credential. `null` when the source provider has been deleted.

          - `type: Literal["federation"]`

            - `"federation"`

          - `updated_at: datetime`

            Entity update timestamp

          - `issuer: Optional[str]`

            Issuer identifier of the identity provider.

          - `provider: Optional[Provider]`

            A Provider is a system that supplies access to Resources and allows actors (Users or Applications) to authenticate.

            - `id: str`

              Unique identifier of the provider

            - `created_at: datetime`

              Entity creation timestamp

            - `identifier: str`

              User specified identifier, unique within the zone

            - `name: str`

              Human-readable name

            - `organization_id: str`

              Organization that owns this provider

            - `owner_type: Literal["platform", "customer"]`

              Who owns this provider. Platform-owned providers cannot be modified via API.

              - `"platform"`

              - `"customer"`

            - `slug: str`

              URL-safe identifier, unique within the zone

            - `updated_at: datetime`

              Entity update timestamp

            - `zone_id: str`

              Zone this provider belongs to

            - `client_id: Optional[str]`

              OAuth 2.0 client identifier

            - `client_secret_set: Optional[bool]`

              Indicates whether a client secret is configured

            - `description: Optional[str]`

              Human-readable description

            - `metadata: Optional[Metadata]`

              Provider metadata

              - `icon_url: Optional[str]`

                Icon URL

            - `protocols: Optional[Protocols]`

              Protocol-specific configuration

              - `oauth2: Optional[ProtocolsOauth2]`

                OAuth 2.0 protocol configuration

                - `issuer: str`

                  OIDC issuer URL used for discovery and token validation.

                - `authorization_endpoint: Optional[str]`

                - `authorization_parameters: Optional[Dict[str, str]]`

                  Custom query parameters appended to authorization redirect URLs. Use for non-standard providers (e.g. Google prompt=consent, access_type=offline).

                - `authorization_resource_enabled: Optional[bool]`

                  Whether to include the resource parameter in authorization requests.

                - `authorization_resource_parameter: Optional[str]`

                  The resource parameter value to include in authorization requests. Defaults to "resource" when authorization_resource_enabled is true.

                - `code_challenge_methods_supported: Optional[List[str]]`

                - `jwks_uri: Optional[str]`

                - `registration_endpoint: Optional[str]`

                - `scope_parameter: Optional[str]`

                  The query parameter name for scopes in authorization requests. Defaults to "scope". Slack v2 uses "user_scope".

                - `scope_separator: Optional[str]`

                  The separator character for scope values. Defaults to " " (space). Slack v2 uses ",".

                - `scopes_supported: Optional[List[str]]`

                - `token_endpoint: Optional[str]`

                - `token_response_access_token_pointer: Optional[str]`

                  Dot-separated path to the access token in the token response body. Defaults to "access_token". Slack v2 uses "authed_user.access_token".

              - `openid: Optional[ProtocolsOpenid]`

                OpenID Connect protocol configuration

                - `external_id_claim: Optional[str]`

                  Name of the OIDC claim carrying the stable external id used to correlate logins with externally provisioned (SCIM) users. Defaults to "sub". Set to "oid" for Entra, whose pairwise "sub" differs from the SCIM externalId.

                - `scopes: Optional[List[str]]`

                  Additional OIDC scopes to request from this provider during authentication (e.g. "groups"). Merged with the default scopes (openid, profile, email).

                - `single_logout_enabled: Optional[bool]`

                  When true, logging out of the zone propagates the logout to this provider's end_session_endpoint (RP-initiated logout). Defaults to false.

                - `user_identifier_claim: Optional[str]`

                  Name of a top-level string claim in this provider's ID Token to use as the user identifier on user creation. When not set, the user's Keycard ID is used.

                - `userinfo_endpoint: Optional[str]`

            - `type: Optional[Literal["external", "keycard-vault", "keycard-sts"]]`

              - `"external"`

              - `"keycard-vault"`

              - `"keycard-sts"`

          - `subject: Optional[str]`

            Subject identifier from the identity provider.

        - `class CredentialIamUserCredentialPassword: …`

          Password credential: the user authenticates with email and password. The email lives on the user.

          - `created_at: datetime`

            Entity creation timestamp

          - `type: Literal["password"]`

            - `"password"`

          - `updated_at: datetime`

            Entity update timestamp

      - `grant_count: Optional[int]`

        Delegated-grant count for this user. Populated only when `expand[]=grant_count` is set on the listing endpoint.

      - `groups: Optional[List[Group]]`

        Groups this user belongs to within the zone. Populated only when `expand[]=groups` is set on the listing endpoint.

        - `id: str`

          Unique identifier of the group

        - `identifier: str`

          Zone-unique slug that policy rules match on.

        - `name: str`

          Human-readable group name

      - `issuer: Optional[str]`

        Issuer identifier of the identity provider

      - `provider_id: Optional[str]`

        Reference to the identity provider. This field is undefined when the source identity provider is deleted but the user is not deleted.

      - `role_assignments: Optional[List[RoleAssignment]]`

        Role grants for this user within the zone. Populated only when `expand[]=role-assignments` is set on the listing endpoint.

        - `role_id: str`

          ID of the assigned role

        - `role_identifier: str`

          Role identifier: a lowercase slug (letters and digits separated by single hyphens or underscores), unique per owner type within a zone. Role identifiers surface in policy evaluation, so the slug restriction keeps them unambiguous in policy text.

        - `role_owner_type: Literal["platform", "customer"]`

          Owner type of the granted role. Disambiguates roles that share an identifier across owner types.

          - `"platform"`

          - `"customer"`

        - `scope: Optional[RoleAssignmentScope]`

          The resource this grant is scoped to, or null when the grant is unscoped (applies to the owning zone itself).

          - `id: str`

            The ID of the scoped resource.

          - `type: str`

            The kind of resource this grant is scoped to (e.g. `zone`).

        - `source: Literal["user", "group"]`

          The principal that holds this grant: `user` when assigned directly to the user, or `group` when inherited through group membership.

          - `"user"`

          - `"group"`

        - `group_id: Optional[str]`

          ID of the group this grant is inherited from. Present only when `source` is `group`.

      - `session_count: Optional[int]`

        Session count for this user. Populated only when `expand[]=session_count` is set on the listing endpoint.

      - `subject: Optional[str]`

        Subject identifier from the identity provider

  - `pagination: Pagination`

    Cursor-based pagination metadata

    - `after_cursor: Optional[str]`

      An opaque cursor used for paginating through a list of results

    - `before_cursor: Optional[str]`

      An opaque cursor used for paginating through a list of results

    - `total_count: Optional[int]`

      Total number of items matching the query. Only included when expand[]=total_count is requested.

### Example

```python
import os
from keycardai_api import KeycardAPI

client = KeycardAPI(
    api_key=os.environ.get("KEYCARD_API_API_KEY"),  # This is the default and can be omitted
)
members = client.zones.groups.members.list(
    group_id="groupId",
    zone_id="zoneId",
)
print(members.items)
```

## Add

`zones.groups.members.add(strgroup_id, MemberAddParams**kwargs)  -> GroupMember`

**post** `/zones/{zoneId}/groups/{groupId}/members`

Adds a user to a group managed in Keycard. Membership of externally synced groups is not managed manually.

### Parameters

- `zone_id: str`

- `group_id: str`

- `user_id: str`

  ID of the user to add to the group

### Returns

- `class GroupMember: …`

  A user's membership in a group

  - `created_at: datetime`

    Entity creation timestamp

  - `user_id: str`

    ID of the user

  - `user: Optional[User]`

    An authenticated user entity

    - `id: str`

      Unique identifier of the user

    - `created_at: datetime`

      Entity creation timestamp

    - `email: str`

      Email address of the user

    - `email_verified: bool`

      Whether the email address has been verified

    - `identifier: str`

      Zone-scoped user identifier. Defaults to the user's Keycard ID. When the provider has user_identifier_claim configured, the value is set from that claim at user creation time.

    - `organization_id: str`

      Organization that owns this user

    - `status: Literal["active", "disabled"]`

      Status of the user. Disabled users cannot authenticate.

      - `"active"`

      - `"disabled"`

    - `updated_at: datetime`

      Entity update timestamp

    - `zone_id: str`

      Zone this user belongs to

    - `authenticated_at: Optional[str]`

      Date when the user was last authenticated

    - `credentials: Optional[List[Credential]]`

      Authentication credentials for this user, each carrying its identity provider for federation credentials. Populated only when `expand[]=credentials` is set on the listing endpoint.

      - `class CredentialIamUserCredentialFederation: …`

        Federation credential: the user authenticates through an identity provider.

        - `created_at: datetime`

          Entity creation timestamp

        - `provider_id: Optional[str]`

          ID of the identity provider backing this credential. `null` when the source provider has been deleted.

        - `type: Literal["federation"]`

          - `"federation"`

        - `updated_at: datetime`

          Entity update timestamp

        - `issuer: Optional[str]`

          Issuer identifier of the identity provider.

        - `provider: Optional[Provider]`

          A Provider is a system that supplies access to Resources and allows actors (Users or Applications) to authenticate.

          - `id: str`

            Unique identifier of the provider

          - `created_at: datetime`

            Entity creation timestamp

          - `identifier: str`

            User specified identifier, unique within the zone

          - `name: str`

            Human-readable name

          - `organization_id: str`

            Organization that owns this provider

          - `owner_type: Literal["platform", "customer"]`

            Who owns this provider. Platform-owned providers cannot be modified via API.

            - `"platform"`

            - `"customer"`

          - `slug: str`

            URL-safe identifier, unique within the zone

          - `updated_at: datetime`

            Entity update timestamp

          - `zone_id: str`

            Zone this provider belongs to

          - `client_id: Optional[str]`

            OAuth 2.0 client identifier

          - `client_secret_set: Optional[bool]`

            Indicates whether a client secret is configured

          - `description: Optional[str]`

            Human-readable description

          - `metadata: Optional[Metadata]`

            Provider metadata

            - `icon_url: Optional[str]`

              Icon URL

          - `protocols: Optional[Protocols]`

            Protocol-specific configuration

            - `oauth2: Optional[ProtocolsOauth2]`

              OAuth 2.0 protocol configuration

              - `issuer: str`

                OIDC issuer URL used for discovery and token validation.

              - `authorization_endpoint: Optional[str]`

              - `authorization_parameters: Optional[Dict[str, str]]`

                Custom query parameters appended to authorization redirect URLs. Use for non-standard providers (e.g. Google prompt=consent, access_type=offline).

              - `authorization_resource_enabled: Optional[bool]`

                Whether to include the resource parameter in authorization requests.

              - `authorization_resource_parameter: Optional[str]`

                The resource parameter value to include in authorization requests. Defaults to "resource" when authorization_resource_enabled is true.

              - `code_challenge_methods_supported: Optional[List[str]]`

              - `jwks_uri: Optional[str]`

              - `registration_endpoint: Optional[str]`

              - `scope_parameter: Optional[str]`

                The query parameter name for scopes in authorization requests. Defaults to "scope". Slack v2 uses "user_scope".

              - `scope_separator: Optional[str]`

                The separator character for scope values. Defaults to " " (space). Slack v2 uses ",".

              - `scopes_supported: Optional[List[str]]`

              - `token_endpoint: Optional[str]`

              - `token_response_access_token_pointer: Optional[str]`

                Dot-separated path to the access token in the token response body. Defaults to "access_token". Slack v2 uses "authed_user.access_token".

            - `openid: Optional[ProtocolsOpenid]`

              OpenID Connect protocol configuration

              - `external_id_claim: Optional[str]`

                Name of the OIDC claim carrying the stable external id used to correlate logins with externally provisioned (SCIM) users. Defaults to "sub". Set to "oid" for Entra, whose pairwise "sub" differs from the SCIM externalId.

              - `scopes: Optional[List[str]]`

                Additional OIDC scopes to request from this provider during authentication (e.g. "groups"). Merged with the default scopes (openid, profile, email).

              - `single_logout_enabled: Optional[bool]`

                When true, logging out of the zone propagates the logout to this provider's end_session_endpoint (RP-initiated logout). Defaults to false.

              - `user_identifier_claim: Optional[str]`

                Name of a top-level string claim in this provider's ID Token to use as the user identifier on user creation. When not set, the user's Keycard ID is used.

              - `userinfo_endpoint: Optional[str]`

          - `type: Optional[Literal["external", "keycard-vault", "keycard-sts"]]`

            - `"external"`

            - `"keycard-vault"`

            - `"keycard-sts"`

        - `subject: Optional[str]`

          Subject identifier from the identity provider.

      - `class CredentialIamUserCredentialPassword: …`

        Password credential: the user authenticates with email and password. The email lives on the user.

        - `created_at: datetime`

          Entity creation timestamp

        - `type: Literal["password"]`

          - `"password"`

        - `updated_at: datetime`

          Entity update timestamp

    - `grant_count: Optional[int]`

      Delegated-grant count for this user. Populated only when `expand[]=grant_count` is set on the listing endpoint.

    - `groups: Optional[List[Group]]`

      Groups this user belongs to within the zone. Populated only when `expand[]=groups` is set on the listing endpoint.

      - `id: str`

        Unique identifier of the group

      - `identifier: str`

        Zone-unique slug that policy rules match on.

      - `name: str`

        Human-readable group name

    - `issuer: Optional[str]`

      Issuer identifier of the identity provider

    - `provider_id: Optional[str]`

      Reference to the identity provider. This field is undefined when the source identity provider is deleted but the user is not deleted.

    - `role_assignments: Optional[List[RoleAssignment]]`

      Role grants for this user within the zone. Populated only when `expand[]=role-assignments` is set on the listing endpoint.

      - `role_id: str`

        ID of the assigned role

      - `role_identifier: str`

        Role identifier: a lowercase slug (letters and digits separated by single hyphens or underscores), unique per owner type within a zone. Role identifiers surface in policy evaluation, so the slug restriction keeps them unambiguous in policy text.

      - `role_owner_type: Literal["platform", "customer"]`

        Owner type of the granted role. Disambiguates roles that share an identifier across owner types.

        - `"platform"`

        - `"customer"`

      - `scope: Optional[RoleAssignmentScope]`

        The resource this grant is scoped to, or null when the grant is unscoped (applies to the owning zone itself).

        - `id: str`

          The ID of the scoped resource.

        - `type: str`

          The kind of resource this grant is scoped to (e.g. `zone`).

      - `source: Literal["user", "group"]`

        The principal that holds this grant: `user` when assigned directly to the user, or `group` when inherited through group membership.

        - `"user"`

        - `"group"`

      - `group_id: Optional[str]`

        ID of the group this grant is inherited from. Present only when `source` is `group`.

    - `session_count: Optional[int]`

      Session count for this user. Populated only when `expand[]=session_count` is set on the listing endpoint.

    - `subject: Optional[str]`

      Subject identifier from the identity provider

### Example

```python
import os
from keycardai_api import KeycardAPI

client = KeycardAPI(
    api_key=os.environ.get("KEYCARD_API_API_KEY"),  # This is the default and can be omitted
)
group_member = client.zones.groups.members.add(
    group_id="groupId",
    zone_id="zoneId",
    user_id="user_id",
)
print(group_member.user_id)
```

## Remove

`zones.groups.members.remove(struser_id, MemberRemoveParams**kwargs)`

**delete** `/zones/{zoneId}/groups/{groupId}/members/{userId}`

Removes a user from a group managed in Keycard. Membership of externally synced groups is not managed manually. A member is identified by its user's ID.

### Parameters

- `zone_id: str`

- `group_id: str`

- `user_id: str`

### Example

```python
import os
from keycardai_api import KeycardAPI

client = KeycardAPI(
    api_key=os.environ.get("KEYCARD_API_API_KEY"),  # This is the default and can be omitted
)
client.zones.groups.members.remove(
    user_id="userId",
    zone_id="zoneId",
    group_id="groupId",
)
```

## Domain Types

### Group Member

- `class GroupMember: …`

  A user's membership in a group

  - `created_at: datetime`

    Entity creation timestamp

  - `user_id: str`

    ID of the user

  - `user: Optional[User]`

    An authenticated user entity

    - `id: str`

      Unique identifier of the user

    - `created_at: datetime`

      Entity creation timestamp

    - `email: str`

      Email address of the user

    - `email_verified: bool`

      Whether the email address has been verified

    - `identifier: str`

      Zone-scoped user identifier. Defaults to the user's Keycard ID. When the provider has user_identifier_claim configured, the value is set from that claim at user creation time.

    - `organization_id: str`

      Organization that owns this user

    - `status: Literal["active", "disabled"]`

      Status of the user. Disabled users cannot authenticate.

      - `"active"`

      - `"disabled"`

    - `updated_at: datetime`

      Entity update timestamp

    - `zone_id: str`

      Zone this user belongs to

    - `authenticated_at: Optional[str]`

      Date when the user was last authenticated

    - `credentials: Optional[List[Credential]]`

      Authentication credentials for this user, each carrying its identity provider for federation credentials. Populated only when `expand[]=credentials` is set on the listing endpoint.

      - `class CredentialIamUserCredentialFederation: …`

        Federation credential: the user authenticates through an identity provider.

        - `created_at: datetime`

          Entity creation timestamp

        - `provider_id: Optional[str]`

          ID of the identity provider backing this credential. `null` when the source provider has been deleted.

        - `type: Literal["federation"]`

          - `"federation"`

        - `updated_at: datetime`

          Entity update timestamp

        - `issuer: Optional[str]`

          Issuer identifier of the identity provider.

        - `provider: Optional[Provider]`

          A Provider is a system that supplies access to Resources and allows actors (Users or Applications) to authenticate.

          - `id: str`

            Unique identifier of the provider

          - `created_at: datetime`

            Entity creation timestamp

          - `identifier: str`

            User specified identifier, unique within the zone

          - `name: str`

            Human-readable name

          - `organization_id: str`

            Organization that owns this provider

          - `owner_type: Literal["platform", "customer"]`

            Who owns this provider. Platform-owned providers cannot be modified via API.

            - `"platform"`

            - `"customer"`

          - `slug: str`

            URL-safe identifier, unique within the zone

          - `updated_at: datetime`

            Entity update timestamp

          - `zone_id: str`

            Zone this provider belongs to

          - `client_id: Optional[str]`

            OAuth 2.0 client identifier

          - `client_secret_set: Optional[bool]`

            Indicates whether a client secret is configured

          - `description: Optional[str]`

            Human-readable description

          - `metadata: Optional[Metadata]`

            Provider metadata

            - `icon_url: Optional[str]`

              Icon URL

          - `protocols: Optional[Protocols]`

            Protocol-specific configuration

            - `oauth2: Optional[ProtocolsOauth2]`

              OAuth 2.0 protocol configuration

              - `issuer: str`

                OIDC issuer URL used for discovery and token validation.

              - `authorization_endpoint: Optional[str]`

              - `authorization_parameters: Optional[Dict[str, str]]`

                Custom query parameters appended to authorization redirect URLs. Use for non-standard providers (e.g. Google prompt=consent, access_type=offline).

              - `authorization_resource_enabled: Optional[bool]`

                Whether to include the resource parameter in authorization requests.

              - `authorization_resource_parameter: Optional[str]`

                The resource parameter value to include in authorization requests. Defaults to "resource" when authorization_resource_enabled is true.

              - `code_challenge_methods_supported: Optional[List[str]]`

              - `jwks_uri: Optional[str]`

              - `registration_endpoint: Optional[str]`

              - `scope_parameter: Optional[str]`

                The query parameter name for scopes in authorization requests. Defaults to "scope". Slack v2 uses "user_scope".

              - `scope_separator: Optional[str]`

                The separator character for scope values. Defaults to " " (space). Slack v2 uses ",".

              - `scopes_supported: Optional[List[str]]`

              - `token_endpoint: Optional[str]`

              - `token_response_access_token_pointer: Optional[str]`

                Dot-separated path to the access token in the token response body. Defaults to "access_token". Slack v2 uses "authed_user.access_token".

            - `openid: Optional[ProtocolsOpenid]`

              OpenID Connect protocol configuration

              - `external_id_claim: Optional[str]`

                Name of the OIDC claim carrying the stable external id used to correlate logins with externally provisioned (SCIM) users. Defaults to "sub". Set to "oid" for Entra, whose pairwise "sub" differs from the SCIM externalId.

              - `scopes: Optional[List[str]]`

                Additional OIDC scopes to request from this provider during authentication (e.g. "groups"). Merged with the default scopes (openid, profile, email).

              - `single_logout_enabled: Optional[bool]`

                When true, logging out of the zone propagates the logout to this provider's end_session_endpoint (RP-initiated logout). Defaults to false.

              - `user_identifier_claim: Optional[str]`

                Name of a top-level string claim in this provider's ID Token to use as the user identifier on user creation. When not set, the user's Keycard ID is used.

              - `userinfo_endpoint: Optional[str]`

          - `type: Optional[Literal["external", "keycard-vault", "keycard-sts"]]`

            - `"external"`

            - `"keycard-vault"`

            - `"keycard-sts"`

        - `subject: Optional[str]`

          Subject identifier from the identity provider.

      - `class CredentialIamUserCredentialPassword: …`

        Password credential: the user authenticates with email and password. The email lives on the user.

        - `created_at: datetime`

          Entity creation timestamp

        - `type: Literal["password"]`

          - `"password"`

        - `updated_at: datetime`

          Entity update timestamp

    - `grant_count: Optional[int]`

      Delegated-grant count for this user. Populated only when `expand[]=grant_count` is set on the listing endpoint.

    - `groups: Optional[List[Group]]`

      Groups this user belongs to within the zone. Populated only when `expand[]=groups` is set on the listing endpoint.

      - `id: str`

        Unique identifier of the group

      - `identifier: str`

        Zone-unique slug that policy rules match on.

      - `name: str`

        Human-readable group name

    - `issuer: Optional[str]`

      Issuer identifier of the identity provider

    - `provider_id: Optional[str]`

      Reference to the identity provider. This field is undefined when the source identity provider is deleted but the user is not deleted.

    - `role_assignments: Optional[List[RoleAssignment]]`

      Role grants for this user within the zone. Populated only when `expand[]=role-assignments` is set on the listing endpoint.

      - `role_id: str`

        ID of the assigned role

      - `role_identifier: str`

        Role identifier: a lowercase slug (letters and digits separated by single hyphens or underscores), unique per owner type within a zone. Role identifiers surface in policy evaluation, so the slug restriction keeps them unambiguous in policy text.

      - `role_owner_type: Literal["platform", "customer"]`

        Owner type of the granted role. Disambiguates roles that share an identifier across owner types.

        - `"platform"`

        - `"customer"`

      - `scope: Optional[RoleAssignmentScope]`

        The resource this grant is scoped to, or null when the grant is unscoped (applies to the owning zone itself).

        - `id: str`

          The ID of the scoped resource.

        - `type: str`

          The kind of resource this grant is scoped to (e.g. `zone`).

      - `source: Literal["user", "group"]`

        The principal that holds this grant: `user` when assigned directly to the user, or `group` when inherited through group membership.

        - `"user"`

        - `"group"`

      - `group_id: Optional[str]`

        ID of the group this grant is inherited from. Present only when `source` is `group`.

    - `session_count: Optional[int]`

      Session count for this user. Populated only when `expand[]=session_count` is set on the listing endpoint.

    - `subject: Optional[str]`

      Subject identifier from the identity provider

### Group Member Create

- `class GroupMemberCreate: …`

  Schema for adding a user to a group

  - `user_id: str`

    ID of the user to add to the group

# Roles

## List

`zones.groups.roles.list(strgroup_id, RoleListParams**kwargs)  -> RoleListResponse`

**get** `/zones/{zoneId}/groups/{groupId}/roles`

Returns the roles assigned to the group. Members inherit these roles. Returns the shared role-assignment shape with `principal_type` set to `group`. Use cursor pagination via `after`/`before`; pass `expand[]=total_count` to include the matching row count. Pass `filter[id]` (repeatable, max 100) to restrict results to a known set of role assignments, mutually exclusive with `after`/`before` (returns 400 if combined). When `filter[id]` is set, `limit` is ignored and the response contains every requested assignment that exists on the group, in a single page. IDs not on the group are silently omitted.

### Parameters

- `zone_id: str`

- `group_id: str`

- `after: Optional[str]`

  Cursor for forward pagination

- `before: Optional[str]`

  Cursor for backward pagination

- `expand: Optional[Union[Literal["total_count"], List[Literal["total_count"]]]]`

  - `Literal["total_count"]`

    - `"total_count"`

  - `List[Literal["total_count"]]`

    - `"total_count"`

- `filter_id: Optional[Union[str, SequenceNotStr[str]]]`

  Restrict results to the role assignment with this ID. Repeatable, max 100. Mutually exclusive with after/before.

  - `str`

    Restrict results to the role assignment with this ID. Repeatable, max 100. Mutually exclusive with after/before.

  - `SequenceNotStr[str]`

- `limit: Optional[int]`

  Maximum number of items to return

### Returns

- `class RoleListResponse: …`

  - `items: List[RoleAssignment]`

    - `id: str`

      Unique identifier of the role assignment

    - `created_at: datetime`

      Entity creation timestamp

    - `principal_id: str`

      ID of the principal the role is assigned to (a user, application, or group ID).

    - `principal_type: str`

      The kind of principal the role is assigned to: `user`, `application`, or `group`. A role assigned to a `group` is inherited by that group's members.

    - `role_id: str`

      ID of the assigned role

    - `role_identifier: str`

      Role identifier: a lowercase slug (letters and digits separated by single hyphens or underscores), unique per owner type within a zone. Role identifiers surface in policy evaluation, so the slug restriction keeps them unambiguous in policy text.

    - `role_owner_type: Literal["platform", "customer"]`

      Owner type of the assigned role. Disambiguates roles that share an identifier across owner types.

      - `"platform"`

      - `"customer"`

    - `updated_at: datetime`

      Entity update timestamp

    - `zone_id: str`

      Zone this assignment belongs to

    - `scope_id: Optional[str]`

      The ID of the scoped resource. Null when the assignment is unscoped.

    - `scope_type: Optional[str]`

      The kind of resource this grant is scoped to (e.g. `zone`). Null when the assignment is unscoped (applies to the owning zone itself).

  - `pagination: Pagination`

    Cursor-based pagination metadata

    - `after_cursor: Optional[str]`

      An opaque cursor used for paginating through a list of results

    - `before_cursor: Optional[str]`

      An opaque cursor used for paginating through a list of results

    - `total_count: Optional[int]`

      Total number of items matching the query. Only included when expand[]=total_count is requested.

### Example

```python
import os
from keycardai_api import KeycardAPI

client = KeycardAPI(
    api_key=os.environ.get("KEYCARD_API_API_KEY"),  # This is the default and can be omitted
)
roles = client.zones.groups.roles.list(
    group_id="groupId",
    zone_id="zoneId",
)
print(roles.items)
```

## Add

`zones.groups.roles.add(strgroup_id, RoleAddParams**kwargs)  -> RoleAssignment`

**post** `/zones/{zoneId}/groups/{groupId}/roles`

Assigns a role to the group; members inherit it. Provide role_id, or role_identifier with owner_type. Returns the shared role-assignment shape with `principal_type` set to `group`.

### Parameters

- `zone_id: str`

- `group_id: str`

- `owner_type: Optional[Literal["platform", "customer"]]`

  Owner type of the role to assign. Required with role_identifier (an identifier is unique only per owner type); must be omitted with role_id.

  - `"platform"`

  - `"customer"`

- `role_id: Optional[str]`

  ID of the role to assign. Provide exactly one of role_id or role_identifier; owner_type must be omitted when role_id is used.

- `role_identifier: Optional[str]`

  Role identifier: a lowercase slug (letters and digits separated by single hyphens or underscores), unique per owner type within a zone. Role identifiers surface in policy evaluation, so the slug restriction keeps them unambiguous in policy text.

- `scope_id: Optional[str]`

  The ID of the resource to scope the grant to. Provide together with scope_type, or omit both for an unscoped assignment. When scope_type is `zone`, this must reference a different zone in the same organization.

- `scope_type: Optional[str]`

  The kind of resource to scope the grant to (e.g. `zone`). Provide together with scope_id, or omit both for an unscoped assignment (applies to the owning zone itself). Only platform roles on the org zone may carry a scope.

### Returns

- `class RoleAssignment: …`

  Represents a role assigned to a principal within a zone

  - `id: str`

    Unique identifier of the role assignment

  - `created_at: datetime`

    Entity creation timestamp

  - `principal_id: str`

    ID of the principal the role is assigned to (a user, application, or group ID).

  - `principal_type: str`

    The kind of principal the role is assigned to: `user`, `application`, or `group`. A role assigned to a `group` is inherited by that group's members.

  - `role_id: str`

    ID of the assigned role

  - `role_identifier: str`

    Role identifier: a lowercase slug (letters and digits separated by single hyphens or underscores), unique per owner type within a zone. Role identifiers surface in policy evaluation, so the slug restriction keeps them unambiguous in policy text.

  - `role_owner_type: Literal["platform", "customer"]`

    Owner type of the assigned role. Disambiguates roles that share an identifier across owner types.

    - `"platform"`

    - `"customer"`

  - `updated_at: datetime`

    Entity update timestamp

  - `zone_id: str`

    Zone this assignment belongs to

  - `scope_id: Optional[str]`

    The ID of the scoped resource. Null when the assignment is unscoped.

  - `scope_type: Optional[str]`

    The kind of resource this grant is scoped to (e.g. `zone`). Null when the assignment is unscoped (applies to the owning zone itself).

### Example

```python
import os
from keycardai_api import KeycardAPI

client = KeycardAPI(
    api_key=os.environ.get("KEYCARD_API_API_KEY"),  # This is the default and can be omitted
)
role_assignment = client.zones.groups.roles.add(
    group_id="groupId",
    zone_id="zoneId",
)
print(role_assignment.id)
```

## Remove

`zones.groups.roles.remove(strrole_id, RoleRemoveParams**kwargs)`

**delete** `/zones/{zoneId}/groups/{groupId}/roles/{roleId}`

Revokes a role from the group. Provide the same (scope_type, scope_id) pair the grant was created with, or omit both to revoke the unscoped grant.

### Parameters

- `zone_id: str`

- `group_id: str`

- `role_id: str`

- `scope_id: Optional[str]`

  Scope target of the grant to revoke. Provide together with scope_type.

- `scope_type: Optional[str]`

  Scope kind of the grant to revoke. Provide together with scope_id.

### Example

```python
import os
from keycardai_api import KeycardAPI

client = KeycardAPI(
    api_key=os.environ.get("KEYCARD_API_API_KEY"),  # This is the default and can be omitted
)
client.zones.groups.roles.remove(
    role_id="roleId",
    zone_id="zoneId",
    group_id="groupId",
)
```
