Threads

Telegram allows commenting on a channel post or on a generic supergroup message, thanks to message threads.

Message threads

Schema:

messageReplyHeader#a6d57763 flags:# reply_to_msg_id:int reply_to_peer_id:flags.0?Peer reply_to_top_id:flags.1?int = MessageReplyHeader;

messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector<Peer> channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies;

message#38116ee0 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true id:int from_id:flags.8?Peer peer_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector<RestrictionReason> ttl_period:flags.25?int = Message;

---functions---

messages.search#a0fda762 flags:# peer:InputPeer q:string from_id:flags.0?InputPeer top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages;

Threads are usually automatically created when replying to any message in a group.
For example, all replies to a message with ID 420 are associated to thread with ID 420, unique to this group; this thread ID is contained in the reply_to_top_id field of reply_to messageReplyHeader, along with an eventual reply_to_msg_id, for replies to messages within a thread.
Replies to messages in a thread are part of the same thread, and do not spawn new threads.

When receiving a message from a group that is also the top of a thread (the message with ID 420), the replies optional field will contain a messageReplies constructor, containing the message ID and PTS of the latest reply in the thread, and the message ID of the latest read thread reply, along with the total number of replies in the thread.

Replies to a thread can also be manually fetched using messages.search, providing to top_msg_id the thread ID.

Channel comments

messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector<Peer> channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies;

The same messageReplies constructor seen above will also be contained in channel posts, this time containing information about the comment section of a specific channel post.
The comment section of a channel post is simply the message thread of the automatically forwarded channel message in the linked discussion supergroup; the ID of the linked discussion supergroup will be contained in the messageReplies.channel_id field.

For channel posts, the recent_repliers field will also contain information about the last few comment posters for a specific thread, to show a small list of commenter profile pictures in client previews.

@replies

messageFwdHeader#5f777dce flags:# imported:flags.7?true from_id:flags.0?Peer from_name:flags.5?string date:int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int psa_type:flags.6?string = MessageFwdHeader;

messageReplyHeader#a6d57763 flags:# reply_to_msg_id:int reply_to_peer_id:flags.0?Peer reply_to_top_id:flags.1?int = MessageReplyHeader;

message#38116ee0 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true id:int from_id:flags.8?Peer peer_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector<RestrictionReason> ttl_period:flags.25?int = Message;

updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update;
updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update;

---functions---

contacts.blockFromReplies#29a8962c flags:# delete_message:flags.0?true delete_history:flags.1?true report_spam:flags.2?true msg_id:int = Updates;

contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer;

Since a user can comment in channel posts without joining the actual discussion supergroup, there must be a way for them to receive notifications about replies in comment sections.
For this reason, a special @replies username is provided. Its ID for main and testing endpoints can be seen in the tdlib sources.

When someone replies to one of our messages in the comment section of a channel post, and the user is not subscribed to the discussion group, the client will receive two updates:

  • An updateNewChannelMessage from the discussion group itself, structured just like any other update coming from a subscribed group, with:
    • id set to the ID of the reply
    • from_id set to the peer that replied to us
    • peer_id set to the peer of the discussion group
    • reply_to.reply_to_msg_id set to the ID of our message
    • reply_to.reply_to_top_id set to the thread ID.
  • An updateNewMessage
    • id set to the common ID sequence for users
    • from_id set to the peer of @replies
    • peer_id set to our own peer
    • fwd_from.saved_from_msg_id set to the ID of the reply
    • fwd_from.from_id set to the the peer that replied to us
    • reply_to.reply_to_peer_id set to the peer of the discussion group
    • reply_to.reply_to_msg_id set to the ID of our message
    • reply_to.reply_to_top_id set to the thread ID

Clients should display messages coming from @replies as a read-only supergroup, with each reply displayed as a separate message from the author of the reply, with a "View in chat" button like for channel comments.