CLEMA protocol

Blocking and Privacy

Blocks and privacy settings are private account state. Their mutations are idempotent, durable, and synchronized to the user's other sessions through the account stream.

User Blocks

{"id":"34","type":"block.add","data":{"operation_id":"block-67890-1","user_id":67890}}

The response and the durable block.added event contain a stable snapshot:

{"id":"34","type":"block.add","seq":"61","ok":true,"data":{"block":{"user_id":67890,"nick":"Former contact","avatar_hash":"a1b2c3d4","blocked_at":"2026-08-05T09:00:00Z"}}}

block.list has no body and returns {"blocks":[...]}. Remove a block with:

{"id":"35","type":"block.remove","data":{"operation_id":"unblock-67890-1","user_id":67890}}

The response and block.removed carry the same block object with "removed":true. Repeating either mutation with the same operation ID returns the original result and does not emit another event.

A block takes precedence over every privacy setting in either direction. It:

Removing a block does not restore the deleted contact. Existing reactions may still be removed and history or messages may still be hidden/deleted. The blocked user receives no block event; an offline presence signal may be sent so clients immediately discard stale online state. Rejected direct operations use the generic not_authorized / Direct interaction is unavailable error. A client should visibly keep the message as unsent, but must not claim that the peer blocked the sender because the same response covers either block direction.

Privacy Settings

privacy.get has no body. New accounts use everyone for every setting:

{"id":"36","type":"privacy.get"}
{"id":"36","type":"privacy.get","ok":true,"data":{"privacy":{"direct_messages":"everyone","group_invites":"everyone","presence":"everyone","phone_discovery":"everyone"}}}

privacy.update accepts one or more changed fields:

{"id":"37","type":"privacy.update","data":{"operation_id":"privacy-1","direct_messages":"contacts","group_invites":"nobody","presence":"contacts"}}
Field Values Meaning
direct_messages everyone, contacts Who may start new direct interactions with the user
group_invites everyone, contacts, nobody Who may add the user or create an addressed invitation
presence everyone, contacts, nobody Who may query or receive the user's presence
phone_discovery everyone, contacts, nobody Whose address book finds the user by their phone number

For contacts, the requesting actor must be in the setting owner's contact list. The response and durable privacy.updated event contain the complete settings object, including updated_at. Presence changes immediately publish the currently allowed state or an offline state to affected online contacts.

Direct-message privacy is checked in the same transaction that creates a text, file or forwarded message. Group privacy is checked atomically by conversation.create, member.add, addressed invite.create, and again when an addressed invitation is accepted; conversation.create and a member.add of several people leave out whoever it refuses and name them instead of failing. A shareable invitation with no target_user_id is an explicit self-join and is unaffected by group_invites; bans still apply normally.