Skip to content

List users (admin)

GET
/admin/users

Paginated admin user list. Newest accounts first. Filters: q runs a case-insensitive substring match across username / fullname / email; status narrows to active / pending / disabled (mapping to the underlying user.approved flag, see 1.17.B for the lifecycle state machine). Cursor pagination via opaque cursor token; total is the unfiltered-by-cursor count for the badge in the chrome.

q
string
<= 200 characters

Case-insensitive substring match across username, fullname, email.

status
string
Allowed values: active pending disabled archived
cursor
string

Opaque token from a previous response’s next_cursor.

limit
integer
default: 50 >= 1 <= 200

A page of admin user rows.

object
items
required
Array<object>

Admin-projection of a user row. Carries everything the admin list table needs — username, email, status, last activity, primary role — without surfacing password-bearing columns. status maps to the underlying user.approved column (1=active, 0=pending, 2=disabled per the lifecycle state machine). primary_role is the user’s alphabetically-first global role assignment; per-team assignments live on the user detail page.

object
ref
required
integer format: int64
username
required
string
fullname
string
nullable
email
string
nullable
display_name
required

Resolved display string (profile.display_name → fullname → username).

string
avatar_url
string
nullable
status
required
string
Allowed values: active pending disabled archived
primary_role

Empty when the user has no global role assigned.

string
created_at
required
string format: date-time
last_active
string format: date-time
nullable
account_expires

Hard expiry enforced at login; null = no expiry.

string format: date-time
nullable
lockout_until

Per-username lockout deadline. Null when the account has never been locked OR the last lockout has been cleared. Values in the past are semantically “unlocked” (auto-clear happens at read time; the stale timestamp stays until the next failed login OR admin unlock). The frontend renders the “Locked (auto-clears at HH:MM)” badge when this > now().

string format: date-time
nullable
failed_login_count

Running count of consecutive failed login attempts. Zero on a fresh row + after any successful login. Threshold-crossing triggers lockout. Surfaced here so admins can see who’s under attack without waiting for a full lockout.

integer format: int32
auth_origin

Login provider for this user — empty / null = native, else ‘simpleldap’ / ‘simplesaml’ / etc. for the enterprise SSO surfaces. Surfaced here so the admin list can show the auth-source badge.

string
nullable
profile_origin_server_id

Federation origin (when the profile row came from a peer instance). Null = home instance. See ADR 0007.

string format: uuid
nullable
total
required

Total rows matching the q + status filter (cursor-independent).

integer format: int64
next_cursor

Opaque pagination token. Pass back as the next request’s cursor param to fetch the following page. Null when this response is the final page.

string
nullable

Authentication required, missing, or invalid

object
error
required

Human-readable error summary

string
Example
the request could not be completed
Example
{
"error": "authentication required: sign in and retry with a valid session or API token"
}

Authenticated but missing required capabilities

object
error
required

Human-readable error summary

string
Example
the request could not be completed

Unexpected server error

object
error
required

Human-readable error summary

string
Example
the request could not be completed