Skip to content

Social Features

Partly out of date

Rendered from ProjectInfo/client/social.md on docs/encryption-modes-spec. Its protocol content is still useful, but parts of it describe an older client or an earlier API. Where it disagrees with the code, the code wins — see the spec errata.

User Profiles

Fetch own profile

GET /api/users/@me
→ User (includes email)

Update own profile

PATCH /api/users/@me
{
  "username": "alice",
  "display_name": "Alice",
  "avatar_url": "/media/attachments/{id}",  // from completed upload
  "banner_url": "/media/attachments/{id}",
  "bio": "string",
  "status": 1,
  "status_text": "Working on something"
}
→ 200 User

Updating profile fields fires USER_UPDATE on the gateway for own sessions.
Updating status/status_text fires PRESENCE_UPDATE.

Status values:

Value Name Display
1 ONLINE Green dot
2 IDLE Yellow/moon
3 DND Red dot
4 OFFLINE Grey dot (or hidden)
5 INVISIBLE Appears as OFFLINE to others; own sessions see ONLINE

Fetch any user's public profile

GET /api/users/{userID}
→ User (no email)

Search users by username (exact)

GET /api/users/search?q=alice
→ User (no email)

Used for the "Add Friend by username" flow.


Uploading an Avatar or Banner

  1. Upload the image file with key_type=public via the media upload flow
  2. Get back the Attachment with id
  3. PATCH /api/users/@me with avatar_url: "/media/attachments/{id}"

To display another user's avatar: 1. GET MEDIA_BASE/media/attachments/{id} → { dek_b64, raw_url } 2. Decrypt the raw image using dek_b64 as a plaintext DEK 3. Render as a blob URL


Friends

Send a friend request

POST /api/users/@me/friends
{ "username": "alice" }
// or
{ "user_id": "uuid" }
→ 204

Errors: 400 (self), 404 (not found), 409 (already friends/pending), 403 (blocked)

List friends (accepted)

GET /api/users/@me/friends
→ User[]

List pending requests

GET /api/users/@me/friends/pending
→ {
    incoming: [{ user_id, username, created_at }],
    outgoing: [{ user_id, username, created_at }]
  }

Accept a friend request

PUT /api/users/@me/friends/{userID}
→ 204

Decline, cancel, or remove

DELETE /api/users/@me/friends/{userID}
→ 204

Works for: declining incoming, cancelling outgoing, removing an accepted friend.


Presence

The presence map tracks online status for all users the client cares about. Update it from:

  • Startup: member list responses include status; friend list responses include status
  • PRESENCE_UPDATE events: { user_id, status, status_text }

Display presence indicators wherever user avatars appear (member list, friend list, DM headers).

Invisible users (status: 5) appear as OFFLINE to everyone except themselves.


Server Members

List server members

GET /api/servers/{serverID}/members?limit=100&offset=0
→ ServerMember[]

limit max 100. Use offset for pagination on large servers. Load lazily — don't pre-fetch all servers on startup.

interface ServerMember {
  server_id: string;
  user_id: string;
  username: string;
  avatar_url: string | null;
  nickname: string | null;
  server_avatar: string | null;
  deaf: boolean;
  mute: boolean;
  timeout_until: string | null;
  joined_at: string;
  roles: string[];  // role IDs
}

Display name priority: nickname ?? display_name ?? username

Search members

GET /api/servers/{serverID}/members/search?q=alice
→ ServerMember[]

Invites

See servers-channels.md for full invite API.

To generate and share a server invite:

  1. POST /api/servers/{serverID}/invites { max_uses, expires_in } → Invite
  2. Share the URL: https://zipp.chat/join/{code}
  3. Recipient opens URL → client fetches GET /api/invites/{code} (no auth) → shows server preview
  4. User confirms → POST /api/invites/{code} (with auth) → joins server

After joining, GET /api/servers/{serverID}/channels to load the channel list.