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:
- rejects new direct text, stored-file, forwarded and online-only transfer interactions, direct edits and new reactions;
- suppresses direct typing, presence, profile lookup, avatar access and search results between the users;
- rejects addressed group/channel additions and invitations between them;
- removes the blocked user from the blocker's contact list and cancels active direct transfers, but preserves message history and shared group membership.
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.