Skip to content

Edit a user's profile (self or moderator)

PATCH
/users/{ref}

Self-edit always allowed; editing other users requires the users.profile.edit.any capability (Admin by default).

ref
required
integer format: int64

PATCH semantics — only present fields are updated, but the schema treats each field as the new full value (no JSON Merge Patch nested ops). Clearing a field is sending an empty string (for text) or null (for nullable URLs).

object
display_name
string
nullable <= 100 characters
bio
string
<= 1000 characters
avatar_url
string
nullable <= 1024 characters
location
string
<= 100 characters
website_url
string format: uri
nullable <= 500 characters
social_links
object
key
additional properties
string
<= 100 characters
language

BCP47 tag, or empty string to reset to “system default”. Validated only loosely server-side — frontend constrains the picker to a known list.

string
<= 35 characters
theme

system follows the OS. Empty string CLEARS the account’s preference, which is not the same thing — a cleared account leaves each device on the app default, an account set to system makes every device follow its own OS.

string
Allowed values: "" light dark system
hide_from_anonymous

Owner opt-out from anonymous profile exposure (ADR 0070 → ADR 0024). Default false. When true, the owner’s public profile page (/users/by-username, /users/by-ref) returns 404 to anonymous viewers even with public mode on. Authenticated viewers and the content-visibility gating are unaffected.

boolean

Updated profile

Merged user + profile view. display_name is the resolved display string, first non-empty of:

authenticated: profile.display_name → user.fullname → username anonymous: profile.display_name → username

The anonymous ladder skips fullname, and has since #478 — real name is authenticated-only (ADR 0070 §3), so a fallback that reached it would defeat that rule silently, for exactly the users who never set a display name. This sentence used to describe only the authenticated ladder, which made the schema the stale source; the rule itself is one Go expression (users.ResolveDisplayName), shared with PostAuthor.

avatar_url is null for users without an uploaded avatar; the frontend renders a generated initials disc in that case.

object
ref
required
integer format: int64
username
required
string
fullname

The raw user.fullname value, for the rare case a caller needs the unresolved string (account settings page). Most UI surfaces should use display_name instead.

string
nullable
display_name
required

Resolved display string ready to render — never empty.

string
bio
string
avatar_url
string
nullable
location
string
website_url
string format: uri
nullable
social_links

Free-form platform → handle map. Frontend renders known platforms (twitter, instagram, artstation, …) as icon links; unknown keys are ignored.

object
key
additional properties
string
language

IETF BCP47 language tag (e.g. “en”, “es-AR”). Empty string = “use system / browser default”. Drives the i18n switcher in the user menu.

string
theme

UI theme preference. system follows the OS; empty string = no stored preference. Persisted alongside the profile so it follows the user across browsers (#677).

string
Allowed values: "" light dark system
member_since
required
string format: date-time
post_count
required

Total live posts authored by this user.

integer format: int64
origin_server_id

Set on profiles mirroring a remote site’s user. NULL = locally-owned account.

string format: uuid
nullable

Malformed request

object
error
required

Human-readable error summary

string
Example
the request could not be completed

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

Resource not found

object
error
required

Human-readable error summary

string
Example
the request could not be completed

Operator has disabled self-edit for the field carried in field. The frontend renders an inline “locked by your administrator” tooltip without blocking other fields.

object
error
required
string
reason
required
string
Allowed values: field_disabled_by_operator
field
required
string