CINXE.COM
Peer database
<!DOCTYPE html> <html class=""> <head> <meta charset="utf-8"> <title>Peer database</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta property="description" content="Many constructors in the API need to be stored in a local database upon reception and should only ever be updated reactively (passively) when received via updates or by other means (as specified in the documentation), to avoid overloading the server by continuously requesting changes for the same unchanged information."> <meta property="og:title" content="Peer database"> <meta property="og:image" content=""> <meta property="og:description" content="Many constructors in the API need to be stored in a local database upon reception and should only ever be updated reactively (passively) when received via updates or by other means (as specified in the documentation), to avoid overloading the server by continuously requesting changes for the same unchanged information."> <link rel="icon" type="image/svg+xml" href="/img/website_icon.svg?4"> <link rel="apple-touch-icon" sizes="180x180" href="/img/apple-touch-icon.png"> <link rel="icon" type="image/png" sizes="32x32" href="/img/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="16x16" href="/img/favicon-16x16.png"> <link rel="alternate icon" href="/img/favicon.ico" type="image/x-icon" /> <link href="/css/bootstrap.min.css?3" rel="stylesheet"> <link href="/css/telegram.css?241" rel="stylesheet" media="screen"> <style> </style> </head> <body class="preload"> <div class="dev_page_wrap"> <div class="dev_page_head navbar navbar-static-top navbar-tg"> <div class="navbar-inner"> <div class="container clearfix"> <ul class="nav navbar-nav navbar-right hidden-xs"><li class="navbar-twitter"><a href="https://twitter.com/telegram" target="_blank" data-track="Follow/Twitter" onclick="trackDlClick(this, event)"><i class="icon icon-twitter"></i><span> Twitter</span></a></li></ul> <ul class="nav navbar-nav"> <li><a href="//telegram.org/">Home</a></li> <li class="hidden-xs"><a href="//telegram.org/faq">FAQ</a></li> <li class="hidden-xs"><a href="//telegram.org/apps">Apps</a></li> <li class="active"><a href="/api">API</a></li> <li class=""><a href="/mtproto">Protocol</a></li> <li class=""><a href="/schema">Schema</a></li> </ul> </div> </div> </div> <div class="container clearfix"> <div class="dev_page"> <div id="dev_page_content_wrap" class=" "> <div class="dev_page_bread_crumbs"><ul class="breadcrumb clearfix"><li><a href="/api" >API</a></li><i class="icon icon-breadcrumb-divider"></i><li><a href="/api/peers" >Peer database</a></li></ul></div> <h1 id="dev_page_title">Peer database</h1> <div id="dev_page_content"><!-- scroll_nav --> <p>Many constructors in the API need to be stored in a local database upon reception and should only ever be updated reactively (passively) when received via updates or by other means (as specified in the documentation), to avoid overloading the server by continuously requesting changes for the same unchanged information. </p> <p><a href="/constructor/user">user</a>, <a href="/constructor/chat">chat</a>, <a href="/constructor/channel">channel</a> constructors and their full counterparts <a href="/constructor/userFull">userFull</a>, <a href="/constructor/chatFull">chatFull</a>, <a href="/constructor/channelFull">channelFull</a> are especially important, because they contain important information about users, bots, chats and channels (from now on, <em>peers</em>), and most importantly the <code>access_hash</code> value, <strong>required</strong> to interact with peers in the API. </p> <p>This page describes exactly how and when should the local databases of the constructors listed above be refreshed, and contains a more detailed description of basic peer-related concepts. </p> <blockquote> <p>For simplicity, the documentation often uses the term "cache" instead of "database" when referring to the peer database, however note that it is recommended to persist received information (or at the very least the id+access hash) to a database, to call methods requiring the access hash and view other peer info without refetching the chat history and peer info after startup. </p> </blockquote> <h3><a class="anchor" href="#peer-info-database" id="peer-info-database" name="peer-info-database"><i class="anchor-icon"></i></a>Peer info database</h3> <pre><code><a href='/constructor/userEmpty'>userEmpty</a>#d3bc4b7a id:<a href='/type/long'>long</a> = <a href='/type/User'>User</a>; <a href='/constructor/user'>user</a>#83314fca flags:<a href='/type/%23'>#</a> self:flags.10?<a href='/constructor/true'>true</a> contact:flags.11?<a href='/constructor/true'>true</a> mutual_contact:flags.12?<a href='/constructor/true'>true</a> deleted:flags.13?<a href='/constructor/true'>true</a> bot:flags.14?<a href='/constructor/true'>true</a> bot_chat_history:flags.15?<a href='/constructor/true'>true</a> bot_nochats:flags.16?<a href='/constructor/true'>true</a> verified:flags.17?<a href='/constructor/true'>true</a> restricted:flags.18?<a href='/constructor/true'>true</a> min:flags.20?<a href='/constructor/true'>true</a> bot_inline_geo:flags.21?<a href='/constructor/true'>true</a> support:flags.23?<a href='/constructor/true'>true</a> scam:flags.24?<a href='/constructor/true'>true</a> apply_min_photo:flags.25?<a href='/constructor/true'>true</a> fake:flags.26?<a href='/constructor/true'>true</a> bot_attach_menu:flags.27?<a href='/constructor/true'>true</a> premium:flags.28?<a href='/constructor/true'>true</a> attach_menu_enabled:flags.29?<a href='/constructor/true'>true</a> flags2:<a href='/type/%23'>#</a> bot_can_edit:flags2.1?<a href='/constructor/true'>true</a> close_friend:flags2.2?<a href='/constructor/true'>true</a> stories_hidden:flags2.3?<a href='/constructor/true'>true</a> stories_unavailable:flags2.4?<a href='/constructor/true'>true</a> contact_require_premium:flags2.10?<a href='/constructor/true'>true</a> bot_business:flags2.11?<a href='/constructor/true'>true</a> bot_has_main_app:flags2.13?<a href='/constructor/true'>true</a> id:<a href='/type/long'>long</a> access_hash:flags.0?<a href='/type/long'>long</a> first_name:flags.1?<a href='/type/string'>string</a> last_name:flags.2?<a href='/type/string'>string</a> username:flags.3?<a href='/type/string'>string</a> phone:flags.4?<a href='/type/string'>string</a> photo:flags.5?<a href='/type/UserProfilePhoto'>UserProfilePhoto</a> status:flags.6?<a href='/type/UserStatus'>UserStatus</a> bot_info_version:flags.14?<a href='/type/int'>int</a> restriction_reason:flags.18?<a href='/type/Vector%20t'>Vector</a><<a href='/type/RestrictionReason'>RestrictionReason</a>> bot_inline_placeholder:flags.19?<a href='/type/string'>string</a> lang_code:flags.22?<a href='/type/string'>string</a> emoji_status:flags.30?<a href='/type/EmojiStatus'>EmojiStatus</a> usernames:flags2.0?<a href='/type/Vector%20t'>Vector</a><<a href='/type/Username'>Username</a>> stories_max_id:flags2.5?<a href='/type/int'>int</a> color:flags2.8?<a href='/type/PeerColor'>PeerColor</a> profile_color:flags2.9?<a href='/type/PeerColor'>PeerColor</a> bot_active_users:flags2.12?<a href='/type/int'>int</a> = <a href='/type/User'>User</a>; <a href='/constructor/chatEmpty'>chatEmpty</a>#29562865 id:<a href='/type/long'>long</a> = <a href='/type/Chat'>Chat</a>; <a href='/constructor/chat'>chat</a>#41cbf256 flags:<a href='/type/%23'>#</a> creator:flags.0?<a href='/constructor/true'>true</a> left:flags.2?<a href='/constructor/true'>true</a> deactivated:flags.5?<a href='/constructor/true'>true</a> call_active:flags.23?<a href='/constructor/true'>true</a> call_not_empty:flags.24?<a href='/constructor/true'>true</a> noforwards:flags.25?<a href='/constructor/true'>true</a> id:<a href='/type/long'>long</a> title:<a href='/type/string'>string</a> photo:<a href='/type/ChatPhoto'>ChatPhoto</a> participants_count:<a href='/type/int'>int</a> date:<a href='/type/int'>int</a> version:<a href='/type/int'>int</a> migrated_to:flags.6?<a href='/type/InputChannel'>InputChannel</a> admin_rights:flags.14?<a href='/type/ChatAdminRights'>ChatAdminRights</a> default_banned_rights:flags.18?<a href='/type/ChatBannedRights'>ChatBannedRights</a> = <a href='/type/Chat'>Chat</a>; <a href='/constructor/chatForbidden'>chatForbidden</a>#6592a1a7 id:<a href='/type/long'>long</a> title:<a href='/type/string'>string</a> = <a href='/type/Chat'>Chat</a>; <a href='/constructor/channel'>channel</a>#aadfc8f flags:<a href='/type/%23'>#</a> creator:flags.0?<a href='/constructor/true'>true</a> left:flags.2?<a href='/constructor/true'>true</a> broadcast:flags.5?<a href='/constructor/true'>true</a> verified:flags.7?<a href='/constructor/true'>true</a> megagroup:flags.8?<a href='/constructor/true'>true</a> restricted:flags.9?<a href='/constructor/true'>true</a> signatures:flags.11?<a href='/constructor/true'>true</a> min:flags.12?<a href='/constructor/true'>true</a> scam:flags.19?<a href='/constructor/true'>true</a> has_link:flags.20?<a href='/constructor/true'>true</a> has_geo:flags.21?<a href='/constructor/true'>true</a> slowmode_enabled:flags.22?<a href='/constructor/true'>true</a> call_active:flags.23?<a href='/constructor/true'>true</a> call_not_empty:flags.24?<a href='/constructor/true'>true</a> fake:flags.25?<a href='/constructor/true'>true</a> gigagroup:flags.26?<a href='/constructor/true'>true</a> noforwards:flags.27?<a href='/constructor/true'>true</a> join_to_send:flags.28?<a href='/constructor/true'>true</a> join_request:flags.29?<a href='/constructor/true'>true</a> forum:flags.30?<a href='/constructor/true'>true</a> flags2:<a href='/type/%23'>#</a> stories_hidden:flags2.1?<a href='/constructor/true'>true</a> stories_hidden_min:flags2.2?<a href='/constructor/true'>true</a> stories_unavailable:flags2.3?<a href='/constructor/true'>true</a> id:<a href='/type/long'>long</a> access_hash:flags.13?<a href='/type/long'>long</a> title:<a href='/type/string'>string</a> username:flags.6?<a href='/type/string'>string</a> photo:<a href='/type/ChatPhoto'>ChatPhoto</a> date:<a href='/type/int'>int</a> restriction_reason:flags.9?<a href='/type/Vector%20t'>Vector</a><<a href='/type/RestrictionReason'>RestrictionReason</a>> admin_rights:flags.14?<a href='/type/ChatAdminRights'>ChatAdminRights</a> banned_rights:flags.15?<a href='/type/ChatBannedRights'>ChatBannedRights</a> default_banned_rights:flags.18?<a href='/type/ChatBannedRights'>ChatBannedRights</a> participants_count:flags.17?<a href='/type/int'>int</a> usernames:flags2.0?<a href='/type/Vector%20t'>Vector</a><<a href='/type/Username'>Username</a>> stories_max_id:flags2.4?<a href='/type/int'>int</a> color:flags2.7?<a href='/type/PeerColor'>PeerColor</a> profile_color:flags2.8?<a href='/type/PeerColor'>PeerColor</a> emoji_status:flags2.9?<a href='/type/EmojiStatus'>EmojiStatus</a> level:flags2.10?<a href='/type/int'>int</a> = <a href='/type/Chat'>Chat</a>; <a href='/constructor/channelForbidden'>channelForbidden</a>#17d493d5 flags:<a href='/type/%23'>#</a> broadcast:flags.5?<a href='/constructor/true'>true</a> megagroup:flags.8?<a href='/constructor/true'>true</a> id:<a href='/type/long'>long</a> access_hash:<a href='/type/long'>long</a> title:<a href='/type/string'>string</a> until_date:flags.16?<a href='/type/int'>int</a> = <a href='/type/Chat'>Chat</a>; <a href='/constructor/inputUserEmpty'>inputUserEmpty</a>#b98886cf = <a href='/type/InputUser'>InputUser</a>; <a href='/constructor/inputUserSelf'>inputUserSelf</a>#f7c1b13f = <a href='/type/InputUser'>InputUser</a>; <a href='/constructor/inputUser'>inputUser</a>#f21158c6 user_id:<a href='/type/long'>long</a> access_hash:<a href='/type/long'>long</a> = <a href='/type/InputUser'>InputUser</a>; <a href='/constructor/inputUserFromMessage'>inputUserFromMessage</a>#1da448e2 peer:<a href='/type/InputPeer'>InputPeer</a> msg_id:<a href='/type/int'>int</a> user_id:<a href='/type/long'>long</a> = <a href='/type/InputUser'>InputUser</a>; // No inputChat, just a long is used (because basic chats don't have access hashes) <a href='/constructor/inputChannelEmpty'>inputChannelEmpty</a>#ee8c1e86 = <a href='/type/InputChannel'>InputChannel</a>; <a href='/constructor/inputChannel'>inputChannel</a>#f35aec28 channel_id:<a href='/type/long'>long</a> access_hash:<a href='/type/long'>long</a> = <a href='/type/InputChannel'>InputChannel</a>; <a href='/constructor/inputChannelFromMessage'>inputChannelFromMessage</a>#5b934f9d peer:<a href='/type/InputPeer'>InputPeer</a> msg_id:<a href='/type/int'>int</a> channel_id:<a href='/type/long'>long</a> = <a href='/type/InputChannel'>InputChannel</a>; <a href='/constructor/inputPeerEmpty'>inputPeerEmpty</a>#7f3b18ea = <a href='/type/InputPeer'>InputPeer</a>; <a href='/constructor/inputPeerSelf'>inputPeerSelf</a>#7da07ec9 = <a href='/type/InputPeer'>InputPeer</a>; <a href='/constructor/inputPeerChat'>inputPeerChat</a>#35a95cb9 chat_id:<a href='/type/long'>long</a> = <a href='/type/InputPeer'>InputPeer</a>; <a href='/constructor/inputPeerUser'>inputPeerUser</a>#dde8a54c user_id:<a href='/type/long'>long</a> access_hash:<a href='/type/long'>long</a> = <a href='/type/InputPeer'>InputPeer</a>; <a href='/constructor/inputPeerChannel'>inputPeerChannel</a>#27bcbbfc channel_id:<a href='/type/long'>long</a> access_hash:<a href='/type/long'>long</a> = <a href='/type/InputPeer'>InputPeer</a>; <a href='/constructor/inputPeerUserFromMessage'>inputPeerUserFromMessage</a>#a87b0a1c peer:<a href='/type/InputPeer'>InputPeer</a> msg_id:<a href='/type/int'>int</a> user_id:<a href='/type/long'>long</a> = <a href='/type/InputPeer'>InputPeer</a>; <a href='/constructor/inputPeerChannelFromMessage'>inputPeerChannelFromMessage</a>#bd2a0840 peer:<a href='/type/InputPeer'>InputPeer</a> msg_id:<a href='/type/int'>int</a> channel_id:<a href='/type/long'>long</a> = <a href='/type/InputPeer'>InputPeer</a>; ---functions--- <a href='/method/users.getUsers'>users.getUsers</a>#d91a548 id:<a href='/type/Vector%20t'>Vector</a><<a href='/type/InputUser'>InputUser</a>> = <a href='/type/Vector%20t'>Vector</a><<a href='/type/User'>User</a>>; <a href='/method/messages.getChats'>messages.getChats</a>#49e9528f id:<a href='/type/Vector%20t'>Vector</a><<a href='/type/long'>long</a>> = <a href='/type/messages.Chats'>messages.Chats</a>; <a href='/method/channels.getChannels'>channels.getChannels</a>#a7f6bbb id:<a href='/type/Vector%20t'>Vector</a><<a href='/type/InputChannel'>InputChannel</a>> = <a href='/type/messages.Chats'>messages.Chats</a>;</code></pre> <p>The peer info database contains the following information: </p> <ul> <li>The <a href="#peer-id">peer ID聽禄</a></li> <li>The <a href="#access-hash">access hash聽禄</a></li> <li><a href="#other-info">Other info聽禄</a></li> </ul> <p>And it must be populated as follows:</p> <ul> <li><a href="#saving-constructors">By saving received user, chat, channel constructors聽禄</a></li> <li><a href="#handling-certain-updates">By handling certain updates聽禄</a></li> <li><a href="#manual-refreshes">By manual refreshes聽禄</a></li> </ul> <p>Example implementation: <a href="https://github.com/tdlib/td/">tdlib</a>.</p> <h4><a class="anchor" href="#saving-constructors" id="saving-constructors" name="saving-constructors"><i class="anchor-icon"></i></a>Saving constructors</h4> <p>The peer info database needs to be updated every time a new constructor of type <a href="/constructor/user">user</a>, <a href="/constructor/chat">chat</a> and <a href="/constructor/channel">channel</a> (and their <code>forbidden</code> counterparts, used for peers that the user can't access, but can view basic info about) is received. </p> <p>These constructors are received when interacting with the API (i.e. in common chats, through the search function, <a href="/api/invites#public-usernames">username resolution</a>, <a href="/api/links#temporary-profile-links">temporary profile links</a>, and so on...). </p> <p>Unless specified otherwise (see the constructor pages for the special cases), when updating the local peer database, all fields from the newly received constructor take priority over the old constructor cached locally (including by removing fields that aren't set in the new constructor). </p> <h4><a class="anchor" href="#handling-certain-updates" id="handling-certain-updates" name="handling-certain-updates"><i class="anchor-icon"></i></a>Handling certain updates</h4> <p>The following updates should trigger an update of a small subset of the info contained in the peer database (both non-full and <a href="#full-info-database">full variants</a>):</p> <ul> <li><a href="/constructor/updateUserStatus">updateUserStatus</a> - Update <a href="/constructor/user">user</a>.<code>status</code></li> <li><a href="/constructor/updateUserName">updateUserName</a>- Update <a href="/constructor/user">user</a>.<code>first_name</code>/<code>last_name</code>/<code>username</code>/<code>usernames</code></li> <li><a href="/constructor/updatePeerBlocked">updatePeerBlocked</a> - Update <a href="/constructor/userFull">userFull</a>.<code>blocked</code>, <a href="/constructor/channelFull">channelFull</a>.<code>blocked</code></li> <li><a href="/constructor/updatePeerSettings">updatePeerSettings</a> - Update <a href="/constructor/userFull">userFull</a>.<code>settings</code></li> <li><a href="/constructor/updatePeerWallpaper">updatePeerWallpaper</a> - Update <a href="/constructor/userFull">userFull</a>.<code>wallpaper</code>, <a href="/constructor/channelFull">channelFull</a>.<code>wallpaper</code></li> <li><a href="/constructor/updateUserEmojiStatus">updateUserEmojiStatus</a> - Update <a href="/constructor/user">user</a>.<code>emoji_status</code></li> <li><a href="/constructor/updateChatParticipants">updateChatParticipants</a> - Update <a href="/constructor/chat">chat</a>.<code>participants_count</code>, <a href="/constructor/chatFull">chatFull</a>.<code>participants</code>. </li> <li><a href="/constructor/updateChatParticipant">updateChatParticipant</a> - Update <a href="/constructor/chat">chat</a>.<code>participants_count</code>, <a href="/constructor/chatFull">chatFull</a>.<code>participants</code>. </li> <li><a href="/constructor/updateChannelAvailableMessages">updateChannelAvailableMessages</a> - Update <a href="/constructor/channel">channel</a>.<code>hidden_prehistory</code></li> </ul> <h4><a class="anchor" href="#manual-refreshes" id="manual-refreshes" name="manual-refreshes"><i class="anchor-icon"></i></a>Manual refreshes</h4> <p>For performance reasons, the server will not always send updates containing updated information about all peers: for this reason, information about <em>already cached</em> peers may be refreshed manually in certain conditions using the bulked <a href="/method/users.getUsers">users.getUsers</a>, <a href="/method/messages.getChats">messages.getChats</a>, <a href="/method/channels.getChannels">channels.getChannels</a> methods, all requiring the previously cached <code>access_hash</code>. </p> <p>The following list is non-exhaustive, and clients may choose to refresh peer information in some other conditions as well (i.e. when opening the profile page, etc). </p> <ul> <li> <p>When fetching info about one of the following internal user IDs, if the info isn't already cached or if the cached info is <code>min</code>: 777000 (service notifications user), 1271266957 (replies bot), 1087968824 (anonymous bot), 136817688 (channel bot), 5434988373 (antispam bot).<br> Info about these IDs may be fetched with the zero access hash even by users. </p> </li> <li> <p>After invoking <a href="/method/bots.setBotInfo">bots.setBotInfo</a> after changing <code>name</code> (but <strong>not</strong> the <code>about</code> or the <code>description</code>, as changing those fields already triggers a refresh of the full info database, and with it the peer database), for the bot whose info we changed</p> </li> <li> <p>After receiving a <code>CHAT_FORWARDS_RESTRICTED</code> error when forwarding messages from a chat, to refresh info about the source chat (i.e. the fact that we received this error means that the client didn't locally prevent the user from forwarding a message from the protected chat, because the locally cached <a href="/constructor/channel">channel</a>.<code>noforwards</code>/<a href="/constructor/chat">chat</a>.<code>noforwards</code> flag is out of date).</p> </li> <li> <p>After receiving a <code>CHAT_GUEST_SEND_FORBIDDEN</code> error when sending messages to a <a href="/api/discussion">discussion group</a>, to refresh info about the discussion group (i.e. the fact that we received this error means that the client didn't locally prevent the non-member user from sending a message to a discussion group where only members can send messages, because the locally cached <a href="/constructor/channel">channel</a>.<code>join_to_send</code> flag is out of date).</p> </li> <li> <p>After receiving a <code>USER_NOT_PARTICIPANT</code> error when calling <a href="/method/channels.leaveChannel">channels.leaveChannel</a>, to refresh info about the channel/supergroup (i.e. the fact that we received this error means that the client tried to leave a channel/supergroup they're not a member of, and the client didn't try to prevent this locally because its <a href="/constructor/channel">channel</a> constructor is out of date). </p> </li> <li> <p>After invoking the following methods (both if the call succeds and after receiving a <code>USERNAME_NOT_MODIFIED</code> error, which is also a success):</p> <ul> <li><a href="/method/account.toggleUsername">account.toggleUsername</a>, <a href="/method/account.reorderUsernames">account.reorderUsernames</a> - For ourselves</li> <li><a href="/method/bots.toggleUsername">bots.toggleUsername</a>, <a href="/method/bots.reorderUsernames">bots.reorderUsernames</a> - For the bot whose username we updated</li> <li><a href="/method/channels.toggleUsername">channels.toggleUsername</a>, <a href="/method/channels.reorderUsernames">channels.reorderUsernames</a> - For the channel whose username we updated</li> </ul> <p>Info should <strong>only</strong> be manually refreshed with a call to <a href="/method/users.getUsers">users.getUsers</a>, <a href="/method/channels.getChannels">channels.getChannels</a> if the new username order/active username cannot be applied locally (i.e. the method call successfully set as active some username that isn't associated to the peer in our local cache, and so on), otherwise the <code>username</code> and <code>usernames</code> fields of the peer info database should be updated locally, using the info that was passed to the toggle/reorder methods by the user. </p> </li> <li> <p>After invoking the following methods, if the user for whom we set the profile photo is <strong>not</strong> returned in <a href="/constructor/photos.photo">photos.photo</a>.<code>users</code>:</p> <ul> <li><a href="/method/photos.updateProfilePhoto">photos.updateProfilePhoto</a></li> <li><a href="/method/photos.uploadProfilePhoto">photos.uploadProfilePhoto</a></li> <li><a href="/method/photos.uploadContactProfilePhoto">photos.uploadContactProfilePhoto</a> - Only if <code>suggest</code> is not set</li> </ul> </li> <li> <p>After invoking <a href="/method/photos.deletePhotos">photos.deletePhotos</a>, if the local cache doesn't have any more photos left for the current user after removing the ones passed to the method. </p> </li> <li> <p>After failing to download a peer photo.</p> </li> <li> <p><a href="/method/contacts.getStatuses">contacts.getStatuses</a> should be invoked by clients every <code>70000-100000</code> seconds to update the <a href="/constructor/user">user</a>.<code>status</code> field of contacts.<br> The exact contact status polling interval should be randomly chosen between <code>70000</code> and <code>100000</code>, and re-chosen every time <a href="/method/contacts.getStatuses">contacts.getStatuses</a> is invoked.<br> If a <a href="/method/contacts.getStatuses">contacts.getStatuses</a> query fails, repeat the method call after <code>5</code> to <code>10</code> seconds.</p> </li> </ul> <h4><a class="anchor" href="#peer-id" id="peer-id" name="peer-id"><i class="anchor-icon"></i></a>Peer ID</h4> <p>The peer <code>id</code> is a unique 64-bit ID used to identify a specific user, chat or channel. </p> <p>This field should be used as primary key in the channel, chat and user databases. </p> <p>Note that the ID sequences of users, chats and channels <strong>overlap</strong>, so you must either:</p> <ul> <li>Use separate tables/hashmaps for <a href="/constructor/user">user</a>s, <a href="/constructor/chat">chat</a>s and <a href="/constructor/channel">channel</a>s OR</li> <li>Transform the peer IDs to bot API IDs as specified <a href="/api/bots/ids">here聽禄</a>, which will allow you to use a single ID sequence (and database) for all three peer types, maintaining uniqueness.<br> In this case, a single table <em>can</em> be used for all peer types, but since the structures of the constructors are different, to avoid useless typechecks it might be a good idea to use three tables, as with the first approach. </li> </ul> <p>It's a good idea to transform peer IDs to <a href="/api/bots/ids">bot API IDs</a> even if you do decide to use separate databases, as it will make IDs more visually recognizable both for you and your users, as well as guarantee compatibility with the bot API.</p> <h4><a class="anchor" href="#access-hash" id="access-hash" name="access-hash"><i class="anchor-icon"></i></a>Access hash</h4> <p>The <code>access_hash</code> is the second most important field stored in the <a href="#peer-info-database">peer database</a>, used to generate <a href="/type/InputPeer">InputPeer</a>, <a href="/type/InputUser">inputUser</a>, <a href="/type/InputChannel">inputChannel</a> constructors used to interact with peers in the API.<br> Note that <a href="/constructor/chat">chat</a>s (<a href="/api/channel">basic groups聽禄</a>) do not have or need an access hash.<br> <a href="/constructor/user">user</a>s and <a href="/constructor/channel">channel</a>s (<a href="/api/channel">supergroups and channels聽禄</a>) have an access hash, and it can come in various flavors:</p> <ul> <li>Full access hash: can be used everywhere in the API.</li> <li>Min access hash: received from <a href="/api/min">min constructors聽禄</a>, can only be used to fetch profile pictures using <a href="/constructor/inputPeerPhotoFileLocation"><code>inputPeerPhotoFileLocation</code>聽禄</a>. </li> <li>From-message access hash: not a real access hash, constructed as specified <a href="/api/min">here聽禄</a>, must be used when only a min access hash is available locally, but a full access hash is required. </li> <li>Zero access hash: equal to <code>0</code>, must be used by bots when only a min access hash (or no access hash) is available locally, but a full access hash is required. </li> </ul> <p>The access hash versions listed above are listed in descending priority, and if a version with higher priority is currently cached, it must not be overwritten with a lower priority version. </p> <p>Access hashes are received when interacting with the API (i.e. in common chats, through the search function, <a href="/api/invites#public-usernames">username resolution</a>, <a href="/api/links#temporary-profile-links">temporary profile links</a>, and so on...): if you have only a user/channel/supergroup ID without any kind of access hash, you <strong>cannot</strong> interact with that peer.<br> Access hashes may not be reused across different accounts or different sessions of the same account.<br> This is a core spam prevention feature of Telegram. </p> <p>Clients and client APIs should avoid exposing access hashes to users, as they cannot be reused outside of the current session, and the user should not be burdened with storing them, when the client can perfectly do the job by itself. </p> <p>Note: some other, non-peer-related constructors (i.e. not <a href="/constructor/user">user</a>, <a href="/constructor/chat">chat</a> or <a href="/constructor/channel">channel</a>) may also contain access hashes, which should be stored in a different database. </p> <h4><a class="anchor" href="#other-info" id="other-info" name="other-info"><i class="anchor-icon"></i></a>Other info</h4> <p>Various other fields commonly used by the client, as specified in the constructor pages (<a href="/constructor/user">user</a>, <a href="/constructor/chat">chat</a> and <a href="/constructor/channel">channel</a>).<br> As specified in the constructor docs, some of the fields must not be overwritten if a <a href="/api/min">min constructor</a> is received, and a change in some other fields must trigger invalidation of the <a href="#full-info-database">full info database聽禄</a>. </p> <h3><a class="anchor" href="#full-info-database" id="full-info-database" name="full-info-database"><i class="anchor-icon"></i></a>Full info database</h3> <pre><code><a href='/constructor/users.userFull'>users.userFull</a>#3b6d152e full_user:<a href='/type/UserFull'>UserFull</a> chats:<a href='/type/Vector%20t'>Vector</a><<a href='/type/Chat'>Chat</a>> users:<a href='/type/Vector%20t'>Vector</a><<a href='/type/User'>User</a>> = <a href='/type/users.UserFull'>users.UserFull</a>; <a href='/constructor/messages.chatFull'>messages.chatFull</a>#e5d7d19c full_chat:<a href='/type/ChatFull'>ChatFull</a> chats:<a href='/type/Vector%20t'>Vector</a><<a href='/type/Chat'>Chat</a>> users:<a href='/type/Vector%20t'>Vector</a><<a href='/type/User'>User</a>> = <a href='/type/messages.ChatFull'>messages.ChatFull</a>; <a href='/constructor/userFull'>userFull</a>#cc997720 flags:<a href='/type/%23'>#</a> blocked:flags.0?<a href='/constructor/true'>true</a> phone_calls_available:flags.4?<a href='/constructor/true'>true</a> phone_calls_private:flags.5?<a href='/constructor/true'>true</a> can_pin_message:flags.7?<a href='/constructor/true'>true</a> has_scheduled:flags.12?<a href='/constructor/true'>true</a> video_calls_available:flags.13?<a href='/constructor/true'>true</a> voice_messages_forbidden:flags.20?<a href='/constructor/true'>true</a> translations_disabled:flags.23?<a href='/constructor/true'>true</a> stories_pinned_available:flags.26?<a href='/constructor/true'>true</a> blocked_my_stories_from:flags.27?<a href='/constructor/true'>true</a> wallpaper_overridden:flags.28?<a href='/constructor/true'>true</a> contact_require_premium:flags.29?<a href='/constructor/true'>true</a> read_dates_private:flags.30?<a href='/constructor/true'>true</a> flags2:<a href='/type/%23'>#</a> sponsored_enabled:flags2.7?<a href='/constructor/true'>true</a> id:<a href='/type/long'>long</a> about:flags.1?<a href='/type/string'>string</a> settings:<a href='/type/PeerSettings'>PeerSettings</a> personal_photo:flags.21?<a href='/type/Photo'>Photo</a> profile_photo:flags.2?<a href='/type/Photo'>Photo</a> fallback_photo:flags.22?<a href='/type/Photo'>Photo</a> notify_settings:<a href='/type/PeerNotifySettings'>PeerNotifySettings</a> bot_info:flags.3?<a href='/type/BotInfo'>BotInfo</a> pinned_msg_id:flags.6?<a href='/type/int'>int</a> common_chats_count:<a href='/type/int'>int</a> folder_id:flags.11?<a href='/type/int'>int</a> ttl_period:flags.14?<a href='/type/int'>int</a> theme_emoticon:flags.15?<a href='/type/string'>string</a> private_forward_name:flags.16?<a href='/type/string'>string</a> bot_group_admin_rights:flags.17?<a href='/type/ChatAdminRights'>ChatAdminRights</a> bot_broadcast_admin_rights:flags.18?<a href='/type/ChatAdminRights'>ChatAdminRights</a> premium_gifts:flags.19?<a href='/type/Vector%20t'>Vector</a><<a href='/type/PremiumGiftOption'>PremiumGiftOption</a>> wallpaper:flags.24?<a href='/type/WallPaper'>WallPaper</a> stories:flags.25?<a href='/type/PeerStories'>PeerStories</a> business_work_hours:flags2.0?<a href='/type/BusinessWorkHours'>BusinessWorkHours</a> business_location:flags2.1?<a href='/type/BusinessLocation'>BusinessLocation</a> business_greeting_message:flags2.2?<a href='/type/BusinessGreetingMessage'>BusinessGreetingMessage</a> business_away_message:flags2.3?<a href='/type/BusinessAwayMessage'>BusinessAwayMessage</a> business_intro:flags2.4?<a href='/type/BusinessIntro'>BusinessIntro</a> birthday:flags2.5?<a href='/type/Birthday'>Birthday</a> personal_channel_id:flags2.6?<a href='/type/long'>long</a> personal_channel_message:flags2.6?<a href='/type/int'>int</a> = <a href='/type/UserFull'>UserFull</a>; <a href='/constructor/chatFull'>chatFull</a>#2633421b flags:<a href='/type/%23'>#</a> can_set_username:flags.7?<a href='/constructor/true'>true</a> has_scheduled:flags.8?<a href='/constructor/true'>true</a> translations_disabled:flags.19?<a href='/constructor/true'>true</a> id:<a href='/type/long'>long</a> about:<a href='/type/string'>string</a> participants:<a href='/type/ChatParticipants'>ChatParticipants</a> chat_photo:flags.2?<a href='/type/Photo'>Photo</a> notify_settings:<a href='/type/PeerNotifySettings'>PeerNotifySettings</a> exported_invite:flags.13?<a href='/type/ExportedChatInvite'>ExportedChatInvite</a> bot_info:flags.3?<a href='/type/Vector%20t'>Vector</a><<a href='/type/BotInfo'>BotInfo</a>> pinned_msg_id:flags.6?<a href='/type/int'>int</a> folder_id:flags.11?<a href='/type/int'>int</a> call:flags.12?<a href='/type/InputGroupCall'>InputGroupCall</a> ttl_period:flags.14?<a href='/type/int'>int</a> groupcall_default_join_as:flags.15?<a href='/type/Peer'>Peer</a> theme_emoticon:flags.16?<a href='/type/string'>string</a> requests_pending:flags.17?<a href='/type/int'>int</a> recent_requesters:flags.17?<a href='/type/Vector%20t'>Vector</a><<a href='/type/long'>long</a>> available_reactions:flags.18?<a href='/type/ChatReactions'>ChatReactions</a> reactions_limit:flags.20?<a href='/type/int'>int</a> = <a href='/type/ChatFull'>ChatFull</a>; <a href='/constructor/channelFull'>channelFull</a>#bbab348d flags:<a href='/type/%23'>#</a> can_view_participants:flags.3?<a href='/constructor/true'>true</a> can_set_username:flags.6?<a href='/constructor/true'>true</a> can_set_stickers:flags.7?<a href='/constructor/true'>true</a> hidden_prehistory:flags.10?<a href='/constructor/true'>true</a> can_set_location:flags.16?<a href='/constructor/true'>true</a> has_scheduled:flags.19?<a href='/constructor/true'>true</a> can_view_stats:flags.20?<a href='/constructor/true'>true</a> blocked:flags.22?<a href='/constructor/true'>true</a> flags2:<a href='/type/%23'>#</a> can_delete_channel:flags2.0?<a href='/constructor/true'>true</a> antispam:flags2.1?<a href='/constructor/true'>true</a> participants_hidden:flags2.2?<a href='/constructor/true'>true</a> translations_disabled:flags2.3?<a href='/constructor/true'>true</a> stories_pinned_available:flags2.5?<a href='/constructor/true'>true</a> view_forum_as_messages:flags2.6?<a href='/constructor/true'>true</a> restricted_sponsored:flags2.11?<a href='/constructor/true'>true</a> can_view_revenue:flags2.12?<a href='/constructor/true'>true</a> paid_media_allowed:flags2.14?<a href='/constructor/true'>true</a> can_view_stars_revenue:flags2.15?<a href='/constructor/true'>true</a> id:<a href='/type/long'>long</a> about:<a href='/type/string'>string</a> participants_count:flags.0?<a href='/type/int'>int</a> admins_count:flags.1?<a href='/type/int'>int</a> kicked_count:flags.2?<a href='/type/int'>int</a> banned_count:flags.2?<a href='/type/int'>int</a> online_count:flags.13?<a href='/type/int'>int</a> read_inbox_max_id:<a href='/type/int'>int</a> read_outbox_max_id:<a href='/type/int'>int</a> unread_count:<a href='/type/int'>int</a> chat_photo:<a href='/type/Photo'>Photo</a> notify_settings:<a href='/type/PeerNotifySettings'>PeerNotifySettings</a> exported_invite:flags.23?<a href='/type/ExportedChatInvite'>ExportedChatInvite</a> bot_info:<a href='/type/Vector%20t'>Vector</a><<a href='/type/BotInfo'>BotInfo</a>> migrated_from_chat_id:flags.4?<a href='/type/long'>long</a> migrated_from_max_id:flags.4?<a href='/type/int'>int</a> pinned_msg_id:flags.5?<a href='/type/int'>int</a> stickerset:flags.8?<a href='/type/StickerSet'>StickerSet</a> available_min_id:flags.9?<a href='/type/int'>int</a> folder_id:flags.11?<a href='/type/int'>int</a> linked_chat_id:flags.14?<a href='/type/long'>long</a> location:flags.15?<a href='/type/ChannelLocation'>ChannelLocation</a> slowmode_seconds:flags.17?<a href='/type/int'>int</a> slowmode_next_send_date:flags.18?<a href='/type/int'>int</a> stats_dc:flags.12?<a href='/type/int'>int</a> pts:<a href='/type/int'>int</a> call:flags.21?<a href='/type/InputGroupCall'>InputGroupCall</a> ttl_period:flags.24?<a href='/type/int'>int</a> pending_suggestions:flags.25?<a href='/type/Vector%20t'>Vector</a><<a href='/type/string'>string</a>> groupcall_default_join_as:flags.26?<a href='/type/Peer'>Peer</a> theme_emoticon:flags.27?<a href='/type/string'>string</a> requests_pending:flags.28?<a href='/type/int'>int</a> recent_requesters:flags.28?<a href='/type/Vector%20t'>Vector</a><<a href='/type/long'>long</a>> default_send_as:flags.29?<a href='/type/Peer'>Peer</a> available_reactions:flags.30?<a href='/type/ChatReactions'>ChatReactions</a> reactions_limit:flags2.13?<a href='/type/int'>int</a> stories:flags2.4?<a href='/type/PeerStories'>PeerStories</a> wallpaper:flags2.7?<a href='/type/WallPaper'>WallPaper</a> boosts_applied:flags2.8?<a href='/type/int'>int</a> boosts_unrestrict:flags2.9?<a href='/type/int'>int</a> emojiset:flags2.10?<a href='/type/StickerSet'>StickerSet</a> = <a href='/type/ChatFull'>ChatFull</a>; ---functions--- <a href='/method/users.getFullUser'>users.getFullUser</a>#b60f5918 id:<a href='/type/InputUser'>InputUser</a> = <a href='/type/users.UserFull'>users.UserFull</a>; <a href='/method/messages.getFullChat'>messages.getFullChat</a>#aeb00b34 chat_id:<a href='/type/long'>long</a> = <a href='/type/messages.ChatFull'>messages.ChatFull</a>; <a href='/method/channels.getFullChannel'>channels.getFullChannel</a>#8736a09 channel:<a href='/type/InputChannel'>InputChannel</a> = <a href='/type/messages.ChatFull'>messages.ChatFull</a>;</code></pre> <p>Example implementation: <a href="https://github.com/tdlib/td/">tdlib</a>.</p> <p>The full info database contains info from the <a href="/constructor/userFull">userFull</a>, <a href="/constructor/chatFull">chatFull</a> and <a href="/constructor/channelFull">channelFull</a> constructors. </p> <p>To populate the full info database for a peer, invoke <a href="/method/users.getFullUser">users.getFullUser</a>, <a href="/method/messages.getFullChat">messages.getFullChat</a>, <a href="/method/channels.getFullChannel">channels.getFullChannel</a>, all requiring the previously cached <a href="#access-hash">access_hash聽禄</a>. </p> <p>Invalidate only <a href="/constructor/userFull">userFull</a> and <a href="/constructor/channelFull">channelFull</a> entries 60 seconds after they are stored.</p> <p>Refresh the full info database when the client needs some data from a full constructor, <strong>and</strong> there is no entry already in the database, or the required entry was invalidated by the TTL, or if:</p> <ul> <li>Some event (specified <a href="#peer-info-database">here聽禄</a>) changes the value of a very specific subset of fields of an entry in the (non-full!) <a href="#peer-info-database">peer info database聽禄</a>.<br> See the documentation in the <a href="/constructor/user">user</a> and <a href="/constructor/channel">channel</a> constructor pages for more info (search for the keyword "invalidate"). </li> <li>When receiving an <a href="/constructor/updateUser">updateUser</a>, <a href="/constructor/updateChat">updateChat</a>, <a href="/constructor/updateChannel">updateChannel</a>, and some other updates, as specified <a href="/type/Update">here聽禄</a></li> <li>After invoking <a href="/method/bots.setBotInfo">bots.setBotInfo</a> (even on error) after changing <code>about</code> or <code>description</code> (but <strong>not</strong> <code>name</code>), for the bot whose info we changed.</li> <li>After invoking <a href="/method/messages.setChatWallPaper">messages.setChatWallPaper</a> to <em>remove</em> the wallpaper and receiving an error, for the peer whose wallpapers we tried to change, to fetch the correct and updated wallpaper settings. </li> <li>After invoking <a href="/method/messages.setChatAvailableReactions">messages.setChatAvailableReactions</a> and getting an error different from <code>CHAT_NOT_MODIFIED</code>, for the peer whose reaction settings we tried to change. </li> <li>After receiving a <code>SEND_AS_PEER_INVALID</code> error from any method that interacts with a group/supergroup: refresh info about the destination, to see which channel peers can be used to send messages to the group/supergroup through send_as.</li> <li>If <a href="/constructor/chat">chat</a>.<code>photo</code> is not equal to <a href="/constructor/chatFull">chatFull</a>.<code>chat_photo</code></li> <li>The <a href="/constructor/channelFull">channelFull</a>.<code>linked_chat_id</code> of channnel/supergroup A is updated to point to channel/supergroup B, but the <a href="/constructor/channelFull">channelFull</a>.<code>linked_chat_id</code> of channel/supergroup B does not point to channel/supergroup A, refresh the <a href="/constructor/channelFull">channelFull</a> of channel/supergroup B.</li> <li>Info about a bot that is a participant to the channel/supergroup is fetched by other means, but the bot is not contained in <a href="/constructor/channelFull">channelFull</a>.<code>bot_info</code>. </li> <li>If <a href="/constructor/channelFull">channelFull</a>.<code>participants_count</code> is less than <a href="/constructor/channelFull">channelFull</a>.<code>admins_count</code> after a local update of the admin list by other means.</li> <li>If the currently logged in user's <a href="/constructor/inputPrivacyKeyStatusTimestamp">inputPrivacyKeyStatusTimestamp</a> <a href="/api/privacy">privacy setting聽禄</a> was changed, refresh the entire <a href="/constructor/userFull">userFull</a> cache for all users. </li> <li>After receiving an error different from <code>USER_NOT_PARTICIPANT</code> when calling <a href="/method/channels.leaveChannel">channels.leaveChannel</a></li> <li>If the profile picture is updated or removed</li> <li>After successfully invoking any of the following methods, for the bot in question:<ul> <li><a href="/method/bots.deletePreviewMedia">bots.deletePreviewMedia</a></li> </ul> </li> <li>After invoking any of the following methods (successfully or not):<ul> <li><a href="/method/bots.setBotGroupDefaultAdminRights">bots.setBotGroupDefaultAdminRights</a> - For the bot</li> <li><a href="/method/bots.setBotBroadcastDefaultAdminRights">bots.setBotBroadcastDefaultAdminRights</a> - For the bot</li> <li><a href="/method/channels.inviteToChannel">channels.inviteToChannel</a> - For the channel/supergroup</li> <li><a href="/method/channels.editAdmin">channels.editAdmin</a> - For the channel/supergroup</li> <li><a href="/method/channels.editCreator">channels.editCreator</a> - For the channel/supergroup</li> </ul> </li> <li>When receiving a <code>CHANNEL_PRIVATE</code> or <code>CHANNEL_PUBLIC_GROUP_NA</code> RPC error.</li> <li>When a channel is made private/public (where previously it was public/private. public=has at least one username, private=has no usernames). </li> <li>If we banned a chat/supergroup participant specifying a <a href="/constructor/chatBannedRights">chatBannedRights</a>.<code>until_date</code>, the full cache of the chat/supergroup should be refresh for the admin at <code>until_date</code>. </li> </ul> <p>The above list is non-exhaustive, and clients may choose to refresh peer information in some other conditions as well (i.e. when opening the profile page, etc). </p> <h3><a class="anchor" href="#quality-of-life-checks" id="quality-of-life-checks" name="quality-of-life-checks"><i class="anchor-icon"></i></a>Quality of life checks</h3> <p>Note the following: peer information is also used for quality-of-life improvements, i.e. to directly prevent the user from doing an operation that is denied by the peer information, instead of allowing the operation and then showing an error. </p> <p>These improvements should be implemented by all clients, however, the server will also always prevent the user from doing illegal operations, by emitting an appropriate <a href="/api/errors">RPC error</a>, as sometimes it is still possible to make an illegal operation, even if a local check <em>is</em> implemented (see below). </p> <p>Instead of (or along with) preventing users from doing illegal operations on the client side, clients should always provide localized versions of errors returned by the server (as listed in the JSON file downloadable from the <a href="/api/errors">RPC error page</a>), to inform the user as to why an attempted operation has failed. </p> <p>In other words, if the client didn't prevent the failed method call locally because:</p> <ul> <li>It does not implement a local check for simplicity or</li> <li>It <em>does</em> implement a local check, but:<ul> <li>Peer info is outdated or</li> <li>An update was sent by the server for the peer info, but it wasn't applied in time due to an (unavoidable!) race condition between the server sending the update and the client sending the query.</li> <li>Other unspecified reasons (a new check introduced in a future layer by a new feature, etc...)</li> </ul> </li> </ul> <p>...it should still let the user know <em>why</em> the query failed, based on the description of the RPC error (if available in the <a href="/api/errors">JSON error database</a>, otherwise by showing the RPC error itself).</p></div> </div> </div> </div> <div class="footer_wrap"> <div class="footer_columns_wrap footer_desktop"> <div class="footer_column footer_column_telegram"> <h5>Telegram</h5> <div class="footer_telegram_description"></div> Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed. </div> <div class="footer_column"> <h5><a href="//telegram.org/faq">About</a></h5> <ul> <li><a href="//telegram.org/faq">FAQ</a></li> <li><a href="//telegram.org/privacy">Privacy</a></li> <li><a href="//telegram.org/press">Press</a></li> </ul> </div> <div class="footer_column"> <h5><a href="//telegram.org/apps#mobile-apps">Mobile Apps</a></h5> <ul> <li><a href="//telegram.org/dl/ios">iPhone/iPad</a></li> <li><a href="//telegram.org/android">Android</a></li> <li><a href="//telegram.org/dl/web">Mobile Web</a></li> </ul> </div> <div class="footer_column"> <h5><a href="//telegram.org/apps#desktop-apps">Desktop Apps</a></h5> <ul> <li><a href="//desktop.telegram.org/">PC/Mac/Linux</a></li> <li><a href="//macos.telegram.org/">macOS</a></li> <li><a href="//telegram.org/dl/web">Web-browser</a></li> </ul> </div> <div class="footer_column footer_column_platform"> <h5><a href="/">Platform</a></h5> <ul> <li><a href="/api">API</a></li> <li><a href="//translations.telegram.org/">Translations</a></li> <li><a href="//instantview.telegram.org/">Instant View</a></li> </ul> </div> </div> <div class="footer_columns_wrap footer_mobile"> <div class="footer_column"> <h5><a href="//telegram.org/faq">About</a></h5> </div> <div class="footer_column"> <h5><a href="//telegram.org/blog">Blog</a></h5> </div> <div class="footer_column"> <h5><a href="//telegram.org/apps">Apps</a></h5> </div> <div class="footer_column"> <h5><a href="/">Platform</a></h5> </div> <div class="footer_column"> <h5><a href="//telegram.org/press">Press</a></h5> </div> </div> </div> </div> <script src="/js/main.js?47"></script> <script src="/js/jquery.min.js?1"></script> <script src="/js/bootstrap.min.js?1"></script> <script>window.initDevPageNav&&initDevPageNav(); backToTopInit("Go up"); removePreloadInit(); </script> </body> </html> <!-- page generated in 10.27ms -->