Organization Users
List organization members and administer their personal settings, profile, and learned preferences
The users endpoint lets organization owners and admins programmatically discover the members of their organization and update each member's personal Pocket configuration — default summary template, AI model, language, notification preferences, encrypted user profile, and learned summarization preferences. Use it to centrally apply opinionated defaults or build custom onboarding flows.
These endpoints are available both as part of the Express organization API (/api/v1/organization/:orgId/users) and as aliases on the public API host (/api/v1/public/users). The public API aliases proxy to the organization API so all encryption, validation, and audit logic lives in one place.
Authentication
All routes accept either authentication mode below.
| Auth | Header | Required role/scope |
|---|---|---|
| Firebase ID token | Authorization: Bearer <firebase_id_token> | Active org member with role owner or admin |
| Organization API key | Authorization: Bearer pk_xxx | Org key for the same organization with the matching scope below |
Personal user API keys (pk_user_*) are intentionally rejected on these routes — they are personal credentials and must not be used to administer other members.
| Operation | Required org key scope |
|---|---|
| List users / read settings bundle | users:read |
| Update settings bundle | users:write |
List Users
GET /api/v1/organization/:orgId/users
GET /api/v1/public/usersReturns a paginated list of active members of the organization. Pending and removed members are excluded. Results are sorted by email ascending.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
q | string | Optional case-insensitive substring match on email or display name |
page | integer | 1-based page number, default 1 |
limit | integer | Items per page (max 100), default 25 |
Response
{
"success": true,
"data": [
{
"user_id": "usr_001",
"email": "alice@example.com",
"display_name": "Alice Liu",
"role": "admin",
"status": "active",
"is_active": true,
"created_at": "2025-12-01T18:42:11.000Z",
"updated_at": "2026-04-08T10:14:22.000Z",
"member_since": "2026-01-04T15:00:00.000Z",
"recording_count": 42,
"latest_recording_at": "2026-04-29T09:21:33.000Z"
}
],
"pagination": {
"page": 1,
"limit": 25,
"total": 1,
"total_pages": 1,
"has_more": false
}
}Get Member Settings
GET /api/v1/organization/:orgId/users/:userId/settings
GET /api/v1/public/users/:user_id/settingsReturns an admin-safe bundle of personal configuration for a single active member. Sensitive sections (profile, preferences, tags) are only included when explicitly requested via the include query parameter.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
include | string | Comma-separated list of optional sections: profile, preferences, tags. The notifications block is included by default; pass none to omit it. |
include_profile | boolean | Alternative per-section flag. Same effect as listing it in include. |
include_preferences | boolean | Alternative per-section flag. |
include_tags | boolean | Alternative per-section flag. |
include_notifications | boolean | Alternative per-section flag. Defaults to true. |
preferences_page | integer | When preferences is included, 1-based page number. Defaults to 1. |
preferences_limit | integer | When preferences is included, page size (max 200). Defaults to 50. |
Response
{
"success": true,
"data": {
"user": {
"user_id": "usr_001",
"email": "alice@example.com",
"display_name": "Alice Liu",
"role": "admin",
"status": "active",
"timezone": "America/Los_Angeles"
},
"settings": {
"conversation_language": "English (US)",
"selected_theme": "auto_detect",
"selected_model": "gemini3FlashPreview",
"auto_transcription": true,
"sync_to_icloud": true,
"auto_add_tasks_from_summaries": true,
"auto_route_enabled": false,
"calendar_matching": false,
"find_pocket_enabled": false,
"monthly_transcription_minutes": 300,
"created_at": "2026-01-04T15:00:00.000Z",
"updated_at": "2026-04-08T10:14:22.000Z"
},
"notifications": {
"highlight_time": "22:00",
"processing_notifications_enabled": true,
"sync_nudges_enabled": true,
"morning_welcome_notifications_enabled": true,
"reminder_notifications_enabled": true
},
"profile": {
"profile": "...decrypted markdown...",
"version": 7
},
"preferences": {
"data": [
{
"id": "pref_001",
"command": "Make summaries more concise",
"command_type": "summary_enhance",
"preference_content": "User prefers concise summaries with bullet points.",
"source_recording_id": null,
"source_summarization_id": null,
"metadata": { "source": "org_admin_api" },
"created_at": "2026-03-01T10:00:00.000Z",
"updated_at": "2026-03-01T10:00:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 1,
"total_pages": 1,
"has_more": false
}
},
"tags": [
{ "id": "tag_001", "name": "1:1s", "color": "#33aaff", "created_at": "...", "updated_at": "..." }
]
}
}Update Member Settings
PATCH /api/v1/organization/:orgId/users/:userId/settings
PATCH /api/v1/public/users/:user_id/settingsApplies an allow-listed subset of changes to the target member. The body may contain any combination of the four sections below; at least one must be supplied. Unknown fields are rejected with 400 INVALID_SETTING.
Request Body
{
"settings": {
"selected_theme": "executive_summary",
"selected_model": "gemini3FlashPreview",
"conversation_language": "English (US)",
"auto_transcription": true
},
"notifications": {
"highlight_time": "22:00",
"reminder_notifications_enabled": true
},
"profile": {
"profile": "Markdown profile that will be encrypted under the target user."
},
"preferences": [
{ "command": "Add follow-ups", "command_type": "manual", "preference_content": "Always include explicit follow-ups." },
{ "id": "pref_005", "preference_content": "Updated wording" },
{ "id": "pref_006", "delete": true }
]
}Behavior Notes
- Settings & notifications — the listed boolean / string fields are validated and merged.
selected_modelis normalized against the active model list and falls back when unknown. - Profile — strings up to 100,000 characters. Stored encrypted under the target user, increments
profile_version, and writes a new row touser_profile_versionswith sourceorg_admin_api. - Preferences — each entry is one of: create (omit
id), update (id+ fields), or delete (id+delete: true). Audit metadata (acting user / org API key id, correlation id,source: "org_admin_api") is merged onto every create/update — even when the entry omits ametadatafield. The LLM classifier is not invoked. - All cross-user mutations are logged with
organization_id, target user id, the actor, the changed sections, and a correlation id. Profile and preference content are never logged.
Response
{
"success": true,
"applied": {
"settings": true,
"notifications": true,
"profile": true,
"preferences_created": 1,
"preferences_updated": 1,
"preferences_deleted": 1
},
"profile_version": 8
}Errors
| Status | Code | Reason |
|---|---|---|
| 400 | EMPTY_PATCH | No section was provided. |
| 400 | INVALID_SETTING / INVALID_PROFILE / INVALID_PREFERENCES | Field-level validation failed. |
| 403 | USER_KEY_NOT_ALLOWED | Personal user API key was used. |
| 403 | ORG_KEY_ORG_MISMATCH | Org API key belongs to a different organization. |
| 403 | INSUFFICIENT_SCOPES | Org API key lacks users:write (or users:read on GET). |
| 404 | MEMBER_NOT_FOUND | Target user is not an active member of this organization. |
