---
title: Users, Groups, and Roles Reference
path: reference/users-and-access
status: published
---

# Users, Groups, and Roles Reference

Endpoints for managing users, groups, and role assignments. For the conceptual model, see [Tenants and Users](../concepts/tenants-and-users.md) and [Permissions and Access](../concepts/permissions-and-access.md).

Identities (users, groups, tenants) are primarily owned by ScaiKey. These endpoints proxy to ScaiKey for writes and surface the local cache for reads.

**Required permission:** Most endpoints require tenant admin or platform admin.

## Users

**Base path:** `/api/v1/admin/users/`

### GET /admin/users/

List users in the current tenant.

**Query parameters:**

| Param | Type | Notes |
|-------|------|-------|
| `page`, `page_size` | integer | Standard pagination |
| `status` | string | `active`, `inactive` |
| `search` | string | Substring match on email or name |

**Response:**

```json
{
  "data": [
    {
      "id": "u_abc123",
      "scaikey_user_id": "usr_...",
      "email": "user@example.com",
      "name": "User Name",
      "status": "active",
      "is_platform_admin": false,
      "is_tenant_admin": false,
      "created_at": "2026-04-01T10:00:00Z"
    }
  ],
  "total": 42,
  "page": 1,
  "page_size": 50
}
```

### GET /admin/users/{user_id}

Get a single user. Accepts either internal UUID or ScaiKey user ID.

### POST /admin/users/

Create a user (proxied to ScaiKey).

**Request:**

| Field | Type | Required |
|-------|------|---------|
| `email` | string | Yes |
| `first_name` | string | No |
| `last_name` | string | No |
| `display_name` | string | No |
| `password` | string | No (if omitted, invite email is sent) |
| `tenant_id` | string | No (defaults to caller's tenant) |

**Response:** Created user.

### PATCH /admin/users/{user_id}

Update user profile fields.

### DELETE /admin/users/{user_id}

Disable user in ScaiKey. Does not hard-delete — the user can be reactivated.

### POST /admin/users/{user_id}/password

Reset a user's password.

**Request:** `{"password": "new-password"}`

### POST /admin/users/invite

Send an invitation email for a new user.

### POST /admin/users/{user_id}/resend-invite

Resend an invitation email.

## Groups

**Base path:** `/api/v1/admin/groups/`

### GET /admin/groups/

List groups in the current tenant.

**Response:**

```json
{
  "data": [
    {
      "id": "g_abc123",
      "name": "DNS Admins",
      "slug": "dns-admins",
      "description": "Tenant-level DNS administrators",
      "group_type": "SECURITY",
      "scope": "tenant",
      "member_count": 3,
      "created_at": "..."
    }
  ]
}
```

### POST /admin/groups/

Create a group.

**Request:**

| Field | Type | Required |
|-------|------|---------|
| `name` | string | Yes |
| `description` | string | No |
| `group_type` | string | No — `SECURITY` (default) or `DISTRIBUTION_LIST` |

### GET /admin/groups/{group_id}

Get a single group.

### PATCH /admin/groups/{group_id}

Update group metadata.

### DELETE /admin/groups/{group_id}

Delete a group. Members are unaffected (their membership is removed).

### GET /admin/groups/{group_id}/members

List group members.

**Response:**

```json
{
  "data": [
    {"user_id": "u_abc", "email": "user@example.com", "joined_at": "..."}
  ],
  "total": 3
}
```

### POST /admin/groups/{group_id}/members

Add a user to a group.

**Request:** `{"member_id": "u_abc123"}`

### DELETE /admin/groups/{group_id}/members/{member_id}

Remove a user from a group.

## Roles

**Base path:** `/api/v1/roles/`

### GET /roles/

List roles available in the tenant.

**Query parameters:**

| Param | Type | Notes |
|-------|------|-------|
| `include_system` | boolean | Include built-in roles (default true) |

**Response:**

```json
{
  "data": [
    {
      "id": "r_platform_admin",
      "name": "platform_admin",
      "description": "Full platform administration",
      "is_system": true,
      "permissions": {
        "domains": ["read", "create", "update", "delete"],
        "records": ["read", "create", "update", "delete"],
        "dnssec": ["read", "enable", "disable", "rotate"],
        "platform": ["config", "audit", "manage_tenants"]
      }
    }
  ]
}
```

### GET /roles/{role_id}

Get a single role.

### POST /roles/

Create a custom role (tenant admin only). Cannot grant permissions the creator doesn't have.

**Request:**

```json
{
  "name": "record-bot",
  "description": "Automation role for record changes",
  "permissions": {
    "records": ["read", "create", "update", "delete"],
    "domains": ["read"]
  }
}
```

### PATCH /roles/{role_id}

Update a custom role (cannot modify system roles).

### DELETE /roles/{role_id}

Delete a custom role. Role assignments referencing it are removed.

### GET /roles/users/{user_id}

List a user's role assignments.

**Response:**

```json
{
  "data": [
    {
      "id": "ur_abc",
      "user_id": "u_xyz",
      "role_id": "r_tenant_admin",
      "role_name": "tenant_admin",
      "scope": "tenant",
      "scope_resource_id": null,
      "expires_at": null,
      "granted_by": "u_admin",
      "granted_at": "..."
    }
  ]
}
```

### POST /roles/users/{user_id}

Assign a role to a user.

**Request:**

```json
{
  "role_id": "r_domain_manager",
  "scope": "domain",
  "scope_resource_id": "d_zone_uuid",
  "expires_at": "2026-12-31T23:59:59Z"
}
```

Scopes: `platform`, `tenant`, `domain`. For `domain` scope, `scope_resource_id` is required.

### DELETE /roles/users/{user_id}/{assignment_id}

Remove a role assignment.

### POST /roles/groups/{group_id}

Assign a role to a group. Members inherit it.

**Request:** Same as user assignment.

### DELETE /roles/groups/{group_id}/{assignment_id}

Remove a group's role assignment.

### GET /roles/users/{user_id}/permissions

Get a user's resolved effective permissions.

**Query parameters:**

| Param | Type | Notes |
|-------|------|-------|
| `domain_id` | string | Include per-domain access grants |

**Response:**

```json
{
  "is_platform_admin": false,
  "is_tenant_admin": true,
  "roles": [
    {"role_name": "tenant_admin", "scope": "tenant", "scope_resource_id": null}
  ],
  "permissions": {
    "domains": ["read", "create", "update", "delete"],
    "records": ["read", "create", "update", "delete"],
    "dnssec": ["read", "enable", "disable", "rotate"]
  }
}
```

## Error codes

| Status | Meaning |
|--------|---------|
| `403` | Caller isn't tenant admin (or platform admin) |
| `404` | User, group, or role not found |
| `409` | Role already assigned with the same scope |
| `422` | Invalid role permissions (can't grant what you don't have) |

## Related

- [Permissions and Access](../concepts/permissions-and-access.md) — how authorization resolves.
- [Tenants and Users](../concepts/tenants-and-users.md) — identity model.
- [Access Grants](../tutorials/access-grants.md) — per-domain delegation.
