CLEMA protocol

User Info

Users can store and retrieve profile information. Fields are inspired by classic ICQ profile and modern messengers.

Every command and event about a profile carries it whole, as profile:

Field Type Description
user_id number User's numeric ID
nick string Display name / nickname
first_name string First name
last_name string Last name
about string About / bio text
birthday string Date of birth: YYYY-MM-DD, or --MM-DD when the year is not told
gender string "male" or "female"
avatar_hash string Avatar hash
bot boolean true for a bot
bot_reads string A bot's: what it hears of the groups it joins, all or addressed
name string A bot's public name
link string A bot's link, <link_base>/<name>, on a server with a link base
commands object A bot's commands, by where they hold
joins_groups boolean A bot's: whether anybody may add it to a group, its group_invites privacy
official boolean true for one of the server's own accounts: the system bot and Mandarin. A client marks them, for nobody to pass for them

A field left out is empty: a client replaces the profile it holds with the one it is given rather than merging the two.

Get User Info

Retrieve profile information for any user by ID, a bot by its name (what its link ends with, in any case), or for yourself (if neither is provided). Giving both is invalid_format; a name that is no bot's is user_not_found.

Request (specific user):

{
  "id": "45",
  "type": "profile.get",
  "data": {
    "user_id": 67890
  }
}

Request (self):

{"id": "45", "type": "profile.get"}

Success:

{
  "id": "45",
  "type": "profile.get",
  "ok": true,
  "data": {
    "profile": {
      "user_id": 67890,
      "nick": "CoolUser",
      "first_name": "John",
      "last_name": "Doe",
      "about": "Hello, I'm using Mandarin!",
      "birthday": "1990-05-15",
      "gender": "male",
      "avatar_hash": "a1b2c3d4"
    }
  }
}

Failure:

{
  "id": "45",
  "type": "profile.get",
  "ok": false,
  "error": {
    "code": "user_not_found",
    "message": "User not found"
  }
}

Update User Info

Update your own profile information. Only provided fields are updated; omitted fields remain unchanged.

Request:

{
  "id": "46",
  "type": "profile.update",
  "data": {
    "operation_id": "0195d1a0-profile",
    "nick": "NewNickname",
    "about": "Updated bio"
  }
}

All fields but operation_id are optional — only include the fields you want to change, and an empty string to clear one.

Field Type Required Description
operation_id string Yes Idempotency key generated once for this logical operation
nick string No Display name / nickname
first_name string No First name
last_name string No Last name
about string No About / bio text
birthday string No Date of birth: YYYY-MM-DD, --MM-DD without the year, or "" to clear it
gender string No Gender: "male", "female", or ""

Success:

{"id": "46", "type": "profile.update", "seq": "47", "ok": true, "data": {"profile": {"user_id": 12345, "nick": "NewNickname", "about": "Updated bio"}}}

The answer carries the profile as the change left it. Setting what the profile already says changes nothing: no event, and no seq.

Profile Changes

A profile is followed by its owner's devices, by everybody who lists the owner as a contact, and by everybody the owner has a direct conversation with that is theirs, unless a block separates the two. A change — profile.update, or an avatar set or removed with PUT /avatars/me or DELETE /avatars/me — is a profile.updated event of each of their account streams, the owner's first:

{
  "type": "profile.updated",
  "seq": "47",
  "data": {
    "profile": {
      "user_id": 67890,
      "nick": "CoolUser",
      "first_name": "John",
      "last_name": "Doe",
      "about": "Updated bio",
      "birthday": "1990-05-15",
      "gender": "male",
      "avatar_hash": "b2c3d4e5"
    }
  }
}

The event is read as its recipient may see the profile when it is delivered: a follower a block now separates from the owner is given the owner's user_id alone. The answer to profile.update stands at the place of the owner's own event. Clients replace their cached profile for this user and refetch the avatar if avatar_hash changed. The nick here is the user's own preferred name — it does not override the names entries have in contact lists (set via contact.rename).

A change of the nick or the picture is also what the members of the owner's groups and channels see of them: it reaches them as member.updated (see Members), however few of them follow the profile.