Departments Domain
The Departments domain provides endpoints for managing departments within a client organization. Departments are organizational groupings that users can be assigned to. A user can belong to multiple departments.
For embedding and endpoint design decisions, see the Design Guidelines.
Endpoints
| Endpoint | Method | Description |
|---|---|---|
| List Departments | GET | Paginated list of departments. Use for tables and dropdowns. |
| Get Department | GET | Fetch a single department directly by ID. |
| Create Department | POST | Create a new department. |
| Update Department | PATCH | Update a department's name or description. |
| Delete Department | DELETE | Delete a department. |
| Add Members | POST | Add users to a department (bulk). |
| Remove Members | POST | Remove users from a department (bulk). |
Getting Users in a Department
To retrieve users belonging to a department, use the List Users endpoint with the department_id filter:
GET /clients/{client_id}/users?department_id=d1a2b3c4-e5f6-7890-abcd-ef1234567890
Users are not embedded in department responses because departments can have hundreds or thousands of members -- an unbounded, paginated relationship. See Why users are not embedded below.
Data Transfer Objects (DTOs)
DepartmentRef
Minimal department reference for embedding inside other domain responses (e.g. User.departments). No joins required beyond the departments table.
{
"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
Used in: Embedded inside User.departments. See Users domain.
Department
Full department representation returned by all department-primary endpoints. Extends DepartmentRef with member count and audit timestamps.
{
"id": "d1a2b3c4-e5f6-7890-abcd-ef1234567890",
"name": "Engineering",
"description": "Software development and infrastructure teams",
"member_count": 45,
"created_at": "2026-02-05T21:29:34.214Z",
"updated_at": "2026-02-05T21:29:34.214Z"
}
| Field | Type | Nullable | Description |
|---|---|---|---|
All DepartmentRef fields | id, name, description -- see DepartmentRef | ||
member_count | integer | No | Number of users currently assigned to this department |
created_at | string (ISO 8601) | No | When this department record was first created |
updated_at | string (ISO 8601) | No | When this department record was last modified |
DB source:
| DTO Field | DB Source |
|---|---|
| (DepartmentRef fields) | see DepartmentRef |
member_count | COUNT(*) from user_departments where department_id = ? AND deleted_at IS NULL |
created_at | departments.created_at |
updated_at | departments.updated_at |
Omitted internal fields: client_id (in URL path), created_by, updated_by, deleted_at, deleted_by
Used in: List Departments, Get Department, Create Department, Update Department
BulkMemberResult
Response shape for Add Members and Remove Members. Always returns 200 OK -- individual failures are reported inline rather than as HTTP errors.
{
"succeeded": [
"a1d97031-04e2-4907-a249-093f7436207b",
"b2e08142-15f3-5018-b350-104g8547318c"
],
"failed": [
{
"id": "ffffffff-ffff-ffff-ffff-ffffffffffff",
"error": "User not found"
}
]
}
| Field | Type | Description |
|---|---|---|
succeeded | string[] | IDs of users successfully added or removed |
failed | object[] | Users that could not be processed |
failed[].id | string (uuid) | The user ID that failed |
failed[].error | string | Human-readable reason for the failure |
Both add and remove are idempotent: adding a user already in the department or removing a user not in the department both count as succeeded.
Why users are not embedded
Department does not include a users array. This is intentional:
| Relationship | Cardinality | Strategy | Reason |
|---|---|---|---|
| User → Departments | 1:few (1–3) | Embed DepartmentRef[] in User | Bounded, always needed, static reference |
| Department → Users | 1:many (100s–1000s) | GET /users?department_id= | Unbounded, needs pagination |
To get users in a department:
GET /clients/{client_id}/users?department_id=d1a2b3c4-e5f6-7890-abcd-ef1234567890
This supports all the standard List Users filters and pagination alongside the department filter.