Users Domain
The Users domain provides endpoints for managing users within a client organization. Users are identified by a stable id and a system-managed username and user_key. Activity timestamps reflect the last time a user was seen across any channel (web or desktop).
For embedding and endpoint design decisions, see the Design Guidelines.
Endpoints
| Endpoint | Method | Description |
|---|---|---|
| List Users | GET | Paginated list of users. Use for tables, dropdowns, and search. |
| Get User | GET | Fetch a single user directly by ID. Use for profile pages, post-update refresh, and cross-domain links. |
| User Summary | GET | Active vs stale user counts with configurable staleness threshold. |
| Update User | PATCH | Update a user's department assignments. |
When to use List vs Get User
| Use case | Endpoint |
|---|---|
| Render a user table with departments | GET /users |
Dropdown or autocomplete (?q=) | GET /users |
| Filter users by department | GET /users?department_id= |
| Load a user profile page by ID | GET /users/{id} |
| Refresh one user after an update | GET /users/{id} |
| Another domain links to a user (e.g. device → user) | GET /users/{id} |
Getting Devices by User
Devices are not embedded in user responses because a user can use many devices over time. Use the List Devices endpoint with the user_id filter:
GET /clients/{client_id}/devices?user_id=a1d97031-04e2-4907-a249-093f7436207b
DTO Hierarchy
UserRef (identity + activity -- no joins)
└── User (UserRef + departments + audit -- requires join)
UserRef is defined here but consumed by other domains (e.g. DeviceUserRef). User is what all user-primary endpoints return.
Data Transfer Objects (DTOs)
UserRef
User reference for embedding inside other domain responses. Think of it as a business card -- enough to identify the user, display their name, and show when they were last active. Contains all fields directly on the users table that are useful in a reference context. No joins required.
The rule for what belongs in UserRef: ask "does every place this user is referenced as a non-primary resource need this field?" If yes, it belongs here. If only the user's own endpoints need it, it belongs in User only.
{
"id": "a1d97031-04e2-4907-a249-093f7436207b",
"username": "mikechang",
"user_key": "mikechang",
"last_activity": {
"at": "2026-02-24T21:23:53.082Z",
"desktop_at": "2026-02-24T21:22:46.119Z",
"web_at": "2026-02-24T21:23:53.082Z"
}
}
| Field | Type | Nullable | Description |
|---|---|---|---|
id | string (uuid) | No | Stable unique identifier for the user |
username | string | No | System-managed username |
user_key | string | No | Unique key used to identify the user within the client (e.g. email or SSO subject) |
last_activity | object | No | Grouped activity timestamps across all channels |
last_activity.at | string (ISO 8601) | Yes | Most recent activity across any channel |
last_activity.desktop_at | string (ISO 8601) | Yes | Most recent desktop agent activity |
last_activity.web_at | string (ISO 8601) | Yes | Most recent web activity |
DB source: users.id, users.username, users.user_key, users.last_activity_utc, users.last_desktop_activity_utc, users.last_web_activity_utc
Used in: Embedded inside other domain responses where a user is referenced but not the primary resource -- e.g. GET /devices/{id}/users, GET /apps/{id}/users, leaderboard responses. Never used as the response shape for user-primary endpoints.
User
Full user representation returned by list, detail, and update endpoints. Extends UserRef with embedded department assignments and audit timestamps.
departments is embedded here because it satisfies all three conditions from the embedding rule: it is bounded (1–3 per user), always needed for display, and static reference data. Devices and apps are unbounded and are exposed as separate sub-resource endpoints instead.
{
"id": "a1d97031-04e2-4907-a249-093f7436207b",
"username": "mikechang",
"user_key": "mikechang",
"last_activity": {
"at": "2026-02-24T21:23:53.082Z",
"desktop_at": "2026-02-24T21:22:46.119Z",
"web_at": "2026-02-24T21:23:53.082Z"
},
"departments": [
{
"id": "d1a2b3c4-e5f6-7890-abcd-ef1234567890",
"name": "Engineering",
"description": "Software development and infrastructure teams"
}
],
"created_at": "2026-02-05T21:29:34.214Z",
"updated_at": "2026-02-05T21:29:34.214Z"
}
| Field | Type | Nullable | Description |
|---|---|---|---|
All UserRef fields | id, username, user_key, last_activity -- see UserRef | ||
departments | DepartmentRef[] | No | Departments this user belongs to. Empty array if unassigned. |
created_at | string (ISO 8601) | No | When this user record was first created |
updated_at | string (ISO 8601) | No | When this user record was last modified |
DB source:
| DTO Field | DB Column |
|---|---|
| (UserRef fields) | see UserRef |
departments | joined via user_departments + departments |
created_at | users.created_at |
updated_at | users.updated_at |
Omitted internal fields: client_id (in URL path), partner_id, created_by, updated_by
Used in: List Users, Get User, Update User
DepartmentRef
Minimal department reference embedded inside User.departments. Defined fully in the Departments domain.
{
"id": "d1a2b3c4-e5f6-7890-abcd-ef1234567890",
"name": "Engineering",
"description": "Software development and infrastructure teams"
}
| Field | Type | Nullable | Description |
|---|---|---|---|
id | string (uuid) | No | Stable unique identifier for the department |
name | string | No | Department display name |
description | string | Yes | Optional department description |
DB source: departments.id, departments.name, departments.description