telegram-crawler/data/web/blogfork.telegram.org/api/auth.html
2022-12-10 22:50:15 +00:00

287 lines
26 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html class="">
<head>
<meta charset="utf-8">
<title>User Authorization</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta property="description" content="How to register a user&#39;s phone to start using the API.">
<meta property="og:title" content="User Authorization">
<meta property="og:image" content="9ebfef6d534b708d3a">
<meta property="og:description" content="How to register a user&#39;s phone to start using the API.">
<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?233" 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/auth" >User Authorization</a></li></ul></div>
<h1 id="dev_page_title">User Authorization</h1>
<div id="dev_page_content"><!-- scroll_nav -->
<p>Authorization is associated with a client's encryption key identifier: <strong>auth_key_id</strong>. No additional parameters need to be passed into methods following authorization. </p>
<p>To log in as a <a href="/bots">bot</a>, follow <a href="/api/bots">these instructions »</a>.</p>
<h3><a class="anchor" href="#sending-a-verification-code" id="sending-a-verification-code" name="sending-a-verification-code"><i class="anchor-icon"></i></a>Sending a verification code</h3>
<p>Example implementations: <a href="https://github.com/DrKLO/Telegram/blob/master/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java">telegram for android</a>, <a href="https://github.com/tdlib/td/tree/master/td/telegram/SendCodeHelper.cpp">tdlib</a>.</p>
<p>To show a nicely formatted and validated phone number field, the <a href="/constructor/help.countriesList">help.countriesList</a> constructor can be obtained using the <a href="/method/help.getCountriesList">help.getCountriesList</a> method.<br>
The <a href="/constructor/help.countriesList">help.countriesList</a> config is then used as described <a href="/api/config#country-information-and-login-phone-patterns">here »</a>. </p>
<p>Then, a text message containing an authorization code is sent to the user's phone using <a href="/method/auth.sendCode">auth.sendCode</a>.<br>
However, this is not always the case, if logout tokens are used: </p>
<h4><a class="anchor" href="#logout-tokens" id="logout-tokens" name="logout-tokens"><i class="anchor-icon"></i></a>Logout tokens</h4>
<p>When invoking <a href="/method/auth.logOut">auth.logOut</a> on a previously authorized session with 2FA enabled, the server may return a <code>future_auth_token</code>, which should be stored in the local database.<br>
At all times, the logout token database should contain at most 20 tokens: evict older tokens as new tokens are added.<br>
When invoking <a href="/method/auth.sendCode">auth.sendCode</a>, all logout tokens present in the database should be provided to <code>codeSettings.logout_tokens</code>.<br>
If any of the logout tokens matches the account we're trying to login into and the token hasn't expired, <a href="/method/auth.sendCode">auth.sendCode</a> will directly return a <code>SESSION_PASSWORD_NEEDED</code> RPC error, directly asking the user to <a href="#2fa">enter the 2FA password</a>, without sending any authorization code. </p>
<p>Otherwise, the system will send an authorization code using the following logic:</p>
<h4><a class="anchor" href="#code-types" id="code-types" name="code-types"><i class="anchor-icon"></i></a>Code types</h4>
<pre><code><a href='/constructor/auth.sentCodeTypeApp'>auth.sentCodeTypeApp</a>#3dbb5986 length:<a href='/type/int'>int</a> = <a href='/type/auth.SentCodeType'>auth.SentCodeType</a>;
<a href='/constructor/auth.sentCodeTypeSms'>auth.sentCodeTypeSms</a>#c000bba2 length:<a href='/type/int'>int</a> = <a href='/type/auth.SentCodeType'>auth.SentCodeType</a>;
<a href='/constructor/auth.sentCodeTypeCall'>auth.sentCodeTypeCall</a>#5353e5a7 length:<a href='/type/int'>int</a> = <a href='/type/auth.SentCodeType'>auth.SentCodeType</a>;
<a href='/constructor/auth.sentCodeTypeFlashCall'>auth.sentCodeTypeFlashCall</a>#ab03c6d9 pattern:<a href='/type/string'>string</a> = <a href='/type/auth.SentCodeType'>auth.SentCodeType</a>;
<a href='/constructor/auth.sentCodeTypeMissedCall'>auth.sentCodeTypeMissedCall</a>#82006484 prefix:<a href='/type/string'>string</a> length:<a href='/type/int'>int</a> = <a href='/type/auth.SentCodeType'>auth.SentCodeType</a>;
<a href='/constructor/auth.sentCodeTypeEmailCode'>auth.sentCodeTypeEmailCode</a>#5a159841 flags:<a href='/type/%23'>#</a> apple_signin_allowed:flags.0?<a href='/constructor/true'>true</a> google_signin_allowed:flags.1?<a href='/constructor/true'>true</a> email_pattern:<a href='/type/string'>string</a> length:<a href='/type/int'>int</a> next_phone_login_date:flags.2?<a href='/type/int'>int</a> = <a href='/type/auth.SentCodeType'>auth.SentCodeType</a>;
<a href='/constructor/auth.sentCodeTypeSetUpEmailRequired'>auth.sentCodeTypeSetUpEmailRequired</a>#a5491dea flags:<a href='/type/%23'>#</a> apple_signin_allowed:flags.0?<a href='/constructor/true'>true</a> google_signin_allowed:flags.1?<a href='/constructor/true'>true</a> = <a href='/type/auth.SentCodeType'>auth.SentCodeType</a>;</code></pre>
<p>The system will automatically choose how to send the authorization code; there are multiple possible ways the code can arrive, signaled to the client via the <a href="/type/auth.SentCodeType">auth.SentCodeType</a> constructor returned by <a href="/method/auth.sendCode">auth.sendCode</a>:</p>
<ul>
<li><a href="/constructor/auth.sentCodeTypeSetUpEmailRequired">auth.sentCodeTypeSetUpEmailRequired</a>: if the user logins often enough, Telegram will ask the user to verify an email that will be used to send the login code.<br>
See <a href="#email-verification">here »</a> for more info on the verification process.</li>
<li><a href="/constructor/auth.sentCodeTypeEmailCode">auth.sentCodeTypeEmailCode</a>: the code was sent to the configured login email.</li>
<li><a href="/constructor/auth.sentCodeTypeApp">auth.sentCodeTypeApp</a>: the code was sent as a Telegram service notification to all other logged-in sessions.</li>
<li><a href="/constructor/auth.sentCodeTypeSms">auth.sentCodeTypeSms</a>: the code was sent via SMS.</li>
<li><a href="/constructor/auth.sentCodeTypeCall">auth.sentCodeTypeCall</a>: the user will receive a phone call and a synthesized voice will tell the user the verification code to input.</li>
<li><a href="/constructor/auth.sentCodeTypeFlashCall">auth.sentCodeTypeFlashCall</a>: the code will be sent via a flash phone call, that will be closed immediately.<br>
In this case, the phone code will then be the phone number itself, just make sure that the phone number matches the specified pattern (see <a href="/constructor/auth.sentCodeTypeFlashCall">auth.sentCodeTypeFlashCall</a>).</li>
<li><a href="/constructor/auth.sentCodeTypeMissedCall">auth.sentCodeTypeMissedCall</a>: the code will be sent via a flash phone call, that will be closed immediately.<br>
The last digits of the phone number that calls are the code that must be entered manually by the user.</li>
<li><a href="/constructor/auth.loggedOut">Logout tokens »</a>: <a href="/method/auth.sendCode">auth.sendCode</a> will directly return a <code>SESSION_PASSWORD_NEEDED</code> RPC error, directly asking the user to <a href="#2fa">enter the 2FA password</a>, without sending any authorization code. </li>
</ul>
<p>The <a href="/method/auth.sendCode">auth.sendCode</a> method also has parameters for enabling/disabling use of flash calls and missed calls, and allows passing an SMS token that will be included in the sent SMS.
For example, the latter is required in newer versions of android, to use the <a href="https://developers.google.com/identity/sms-retriever/overview">android SMS receiver APIs</a>.</p>
<p>The returned <a href="/type/auth.SentCode">auth.SentCode</a> object will contain multiple parameters:</p>
<table class="table">
<tbody>
<tr>
<td><strong>flags</strong></td>
<td style="text-align: center;"><a href="/type/%23">#</a></td>
<td>Flags, see <a href="/mtproto/TL-combinators#conditional-fields">TL conditional fields</a></td>
</tr>
<tr>
<td><strong>type</strong></td>
<td style="text-align: center;"><a href="/type/auth.SentCodeType">auth.SentCodeType</a></td>
<td>Phone code type</td>
</tr>
<tr>
<td><strong>phone_code_hash</strong></td>
<td style="text-align: center;"><a href="/type/string">string</a></td>
<td>Phone code hash, to be stored and later re-used with <a href="/method/auth.signIn">auth.signIn</a></td>
</tr>
<tr>
<td><strong>next_type</strong></td>
<td style="text-align: center;"><a href="/mtproto/TL-combinators#conditional-fields">flags</a>.1?<a href="/type/auth.CodeType">auth.CodeType</a></td>
<td>Phone code type that will be sent next, if the phone code is not received within <code>timeout</code> seconds: to send it use <a href="/method/auth.resendCode">auth.resendCode</a></td>
</tr>
<tr>
<td><strong>timeout</strong></td>
<td style="text-align: center;"><a href="/mtproto/TL-combinators#conditional-fields">flags</a>.2?<a href="/type/int">int</a></td>
<td>Timeout for reception of the phone code</td>
</tr>
</tbody>
</table>
<p>If the message takes too long (<code>timeout</code> seconds) to arrive at the phone, the <a href="/method/auth.resendCode">auth.resendCode</a> method may be invoked to resend a code of type <code>next_type</code>.
If the same happens again, you can use <a href="/method/auth.resendCode">auth.resendCode</a> with the <code>next_type</code> returned by the previous call to <a href="/method/auth.resendCode">auth.resendCode</a>.
To cancel the verification code use <a href="/method/auth.cancelCode">auth.cancelCode</a>.</p>
<h3><a class="anchor" href="#email-verification" id="email-verification" name="email-verification"><i class="anchor-icon"></i></a>Email verification</h3>
<pre><code><a href='/constructor/auth.sentCodeTypeSetUpEmailRequired'>auth.sentCodeTypeSetUpEmailRequired</a>#a5491dea flags:<a href='/type/%23'>#</a> apple_signin_allowed:flags.0?<a href='/constructor/true'>true</a> google_signin_allowed:flags.1?<a href='/constructor/true'>true</a> = <a href='/type/auth.SentCodeType'>auth.SentCodeType</a>;
<a href='/constructor/emailVerifyPurposeLoginSetup'>emailVerifyPurposeLoginSetup</a>#4345be73 phone_number:<a href='/type/string'>string</a> phone_code_hash:<a href='/type/string'>string</a> = <a href='/type/EmailVerifyPurpose'>EmailVerifyPurpose</a>;
<a href='/constructor/emailVerificationCode'>emailVerificationCode</a>#922e55a9 code:<a href='/type/string'>string</a> = <a href='/type/EmailVerification'>EmailVerification</a>;
<a href='/constructor/emailVerificationGoogle'>emailVerificationGoogle</a>#db909ec2 token:<a href='/type/string'>string</a> = <a href='/type/EmailVerification'>EmailVerification</a>;
<a href='/constructor/emailVerificationApple'>emailVerificationApple</a>#96d074fd token:<a href='/type/string'>string</a> = <a href='/type/EmailVerification'>EmailVerification</a>;
<a href='/constructor/account.sentEmailCode'>account.sentEmailCode</a>#811f854f email_pattern:<a href='/type/string'>string</a> length:<a href='/type/int'>int</a> = <a href='/type/account.SentEmailCode'>account.SentEmailCode</a>;
<a href='/constructor/account.emailVerifiedLogin'>account.emailVerifiedLogin</a>#e1bb0d61 email:<a href='/type/string'>string</a> sent_code:<a href='/type/auth.SentCode'>auth.SentCode</a> = <a href='/type/account.EmailVerified'>account.EmailVerified</a>;
<a href='/constructor/emailVerifyPurposeLoginChange'>emailVerifyPurposeLoginChange</a>#527d22eb = <a href='/type/EmailVerifyPurpose'>EmailVerifyPurpose</a>;
<a href='/constructor/account.emailVerified'>account.emailVerified</a>#2b96cd1b email:<a href='/type/string'>string</a> = <a href='/type/account.EmailVerified'>account.EmailVerified</a>;
---functions---
<a href='/method/account.sendVerifyEmailCode'>account.sendVerifyEmailCode</a>#98e037bb purpose:<a href='/type/EmailVerifyPurpose'>EmailVerifyPurpose</a> email:<a href='/type/string'>string</a> = <a href='/type/account.SentEmailCode'>account.SentEmailCode</a>;
<a href='/method/account.verifyEmail'>account.verifyEmail</a>#32da4cf purpose:<a href='/type/EmailVerifyPurpose'>EmailVerifyPurpose</a> verification:<a href='/type/EmailVerification'>EmailVerification</a> = <a href='/type/account.EmailVerified'>account.EmailVerified</a>;</code></pre>
<p>Telegram may return a <a href="/constructor/auth.sentCodeTypeSetUpEmailRequired">auth.sentCodeTypeSetUpEmailRequired</a> code type in the <a href="/constructor/auth.sentCode">auth.sentCode</a> constructor returned by <a href="/method/auth.sendCode">auth.sendCode</a>.<br>
In this case, clients should ask the user to verify an email address that will be used to receive the login code as follows: </p>
<ul>
<li>
<p>If the <code>google_signin_allowed</code> or <code>apple_signin_allowed</code> flags are set, users can directly verify their email with Google/Apple ID as specified <a href="https://developers.google.com/identity/sign-in/android/sign-in">here (Google ID) »</a> and <a href="https://developer.apple.com/documentation/sign_in_with_apple">here (Apple ID) »</a>.<br>
After obtaining the ID token, call <a href="/method/account.verifyEmail">account.verifyEmail</a>, providing the following parameters:</p>
<ul>
<li><code>purpose</code> - A <a href="/constructor/emailVerifyPurposeLoginSetup">emailVerifyPurposeLoginSetup</a> constructor</li>
<li><code>purpose.phone_number</code> - The phone number used with <a href="/method/auth.sendCode">auth.sendCode</a></li>
<li><code>purpose.phone_code_hash</code> - The phone code hash contained in the <a href="/constructor/auth.sentCode">auth.sentCode</a> constructor returned by <a href="/method/auth.sendCode">auth.sendCode</a></li>
<li><code>verification</code> - <a href="/constructor/emailVerificationGoogle">emailVerificationGoogle</a> or <a href="/constructor/emailVerificationApple">emailVerificationApple</a></li>
<li><code>verification.token</code> - The ID token returned by the Google ID API.</li>
</ul>
<p>On success, the <a href="/method/account.verifyEmail">account.verifyEmail</a> method will return a <a href="/constructor/account.emailVerifiedLogin">account.emailVerifiedLogin</a> constructor with an <a href="/constructor/auth.sentCode">auth.sentCode</a> constructor that should be handled <a href="#code-types">as usual »</a>. </p>
</li>
<li>
<p>Otherwise, ask the user to enter an email address and then call <a href="/method/account.sendVerifyEmailCode">account.sendVerifyEmailCode</a>, providing the following parameters:</p>
<ul>
<li><code>email</code> - The email address</li>
<li><code>purpose</code> - A <a href="/constructor/emailVerifyPurposeLoginSetup">emailVerifyPurposeLoginSetup</a> constructor</li>
<li><code>purpose.phone_number</code> - The phone number used with <a href="/method/auth.sendCode">auth.sendCode</a></li>
<li><code>purpose.phone_code_hash</code> - The phone code hash contained in the <a href="/constructor/auth.sentCode">auth.sentCode</a> constructor returned by <a href="/method/auth.sendCode">auth.sendCode</a></li>
</ul>
<p>Once the user receives and inputs the verification code, call <a href="/method/account.verifyEmail">account.verifyEmail</a>, providing the following parameters:</p>
<ul>
<li><code>purpose</code> - A <a href="/constructor/emailVerifyPurposeLoginSetup">emailVerifyPurposeLoginSetup</a> constructor</li>
<li><code>purpose.phone_number</code> - The phone number used with <a href="/method/auth.sendCode">auth.sendCode</a></li>
<li><code>purpose.phone_code_hash</code> - The phone code hash contained in the <a href="/constructor/auth.sentCode">auth.sentCode</a> constructor returned by <a href="/method/auth.sendCode">auth.sendCode</a></li>
<li><code>verification</code> - <a href="/constructor/emailVerificationCode">emailVerificationCode</a></li>
<li><code>verification.code</code> - The verification code received by the user.</li>
</ul>
<p>On success, the <a href="/method/account.verifyEmail">account.verifyEmail</a> method will return a <a href="/constructor/account.emailVerifiedLogin">account.emailVerifiedLogin</a> constructor with an <a href="/constructor/auth.sentCode">auth.sentCode</a> constructor that should be handled <a href="#code-types">as usual »</a>. </p>
</li>
</ul>
<p>To change the login email after login, pass <a href="/constructor/emailVerifyPurposeLoginChange">emailVerifyPurposeLoginChange</a> as <code>purpose</code>, following the exact same Google ID/Apple ID/email code login flow as above: on success, the <a href="/method/account.verifyEmail">account.verifyEmail</a> method will return an <a href="/constructor/account.emailVerified">account.emailVerified</a> constructor.</p>
<h3><a class="anchor" href="#sign-insign-up" id="sign-insign-up" name="sign-insign-up"><i class="anchor-icon"></i></a>Sign in/sign up</h3>
<p>When user enters verification code, the <a href="/method/auth.signIn">auth.signIn</a> method must be used to validate it and possibly sign user in.</p>
<p>If the code was entered correctly, but the method returns <a href="/constructor/auth.authorizationSignUpRequired">auth.authorizationSignUpRequired</a>, it means that account with this phone number doesn't exist yet: user needs to provide basic information, accept terms of service and then the new user registration method (<a href="/method/auth.signUp">auth.signUp</a>) must be invoked.</p>
<h3><a class="anchor" href="#2fa" id="2fa" name="2fa"><i class="anchor-icon"></i></a>2FA</h3>
<p>When trying to sign in using <a href="/method/auth.signIn">auth.signIn</a>, an <a href="/method/auth.signIn#possible-errors">error 400 SESSION_PASSWORD_NEEDED</a> may be returned, if the user has two-factor authentication enabled.
In this case, instructions for <a href="/api/srp">SRP 2FA authentication</a> must be followed.</p>
<p>To set up two-factor authorization on an already authorized account, follow the <a href="/api/srp">SRP 2FA authentication docs</a>.</p>
<h4><a class="anchor" href="#test-accounts" id="test-accounts" name="test-accounts"><i class="anchor-icon"></i></a>Test Accounts</h4>
<p>Each phone number is limited to only a certain amount of logins per day (e.g. 5, but this is subject to change) after which the API will return a FLOOD error until the next day. This might not be enough for testing the implementation of User Authorization flows in client applications.</p>
<p>There are several reserved phone number prefixes for testing that your application handles redirects between DCs, sign up, sign in and 2FA flows correctly. These numbers are only available on <strong>Test DCs</strong> (their IP addresses for TCP transport are available in <a href="https://my.telegram.org/apps">API development tools</a> panel after <a href="https://core.telegram.org/api/obtaining_api_id#obtaining-api-id">api_id was obtained</a>, <a href="https://core.telegram.org/mtproto/transports#uri-format">URI format</a> for HTTPS/Websocket transport).</p>
<p>If you wish to emulate an application of a user associated with DC number X, it is sufficient to specify the phone number as <code>99966XYYYY</code>, where YYYY are random numbers, when registering the user. A user like this would always get XXXXX as the login confirmation code (the DC number, repeated five times). Note that the value of X must be in the range of 1-3 because there are only 3 Test DCs. When the flood limit is reached for any particular test number, just choose another number (changing the YYYY random part).</p>
<p>Do not store any important or private information in the messages of such test accounts; anyone can make use of the simplified authorization mechanism and we periodically wipe all information stored there.</p>
<p>Proceed with User Authorization flows in <strong>Production DCs</strong> only after you make sure everything works correctly on <strong>Test DCs</strong> first to avoid reaching flood limits.</p>
<blockquote>
<p>To help you with working on production DCs, logins with the same phone number with which the <code>api_id</code> was registered have more generous flood limits.</p>
</blockquote>
<h3><a class="anchor" href="#we-are-authorized" id="we-are-authorized" name="we-are-authorized"><i class="anchor-icon"></i></a>We are authorized</h3>
<p>As a result of authorization, the client key, <strong>auth_key_id</strong>, becomes associated with the user, and each subsequent API call with this key will be executed with that user's identity. The authorization method itself returns the relevant user. It is best to immediately store the User ID locally in a binding with the key.</p>
<p>Only a small portion of the API methods are available to <strong>unauthorized</strong> users:</p>
<ul>
<li><a href="/method/auth.sendCode">auth.sendCode</a></li>
<li><a href="/method/auth.resendCode">auth.resendCode</a></li>
<li><a href="/method/account.getPassword">account.getPassword</a></li>
<li><a href="/method/auth.checkPassword">auth.checkPassword</a></li>
<li><a href="/method/auth.checkPhone">auth.checkPhone</a></li>
<li><a href="/method/auth.signUp">auth.signUp</a></li>
<li><a href="/method/auth.signIn">auth.signIn</a></li>
<li><a href="/method/auth.importAuthorization">auth.importAuthorization</a></li>
<li><a href="/method/help.getConfig">help.getConfig</a></li>
<li><a href="/method/help.getNearestDc">help.getNearestDc</a></li>
<li><a href="/method/help.getAppUpdate">help.getAppUpdate</a></li>
<li><a href="/method/help.getCdnConfig">help.getCdnConfig</a></li>
<li><a href="/method/langpack.getLangPack">langpack.getLangPack</a></li>
<li><a href="/method/langpack.getStrings">langpack.getStrings</a></li>
<li><a href="/method/langpack.getDifference">langpack.getDifference</a></li>
<li><a href="/method/langpack.getLanguages">langpack.getLanguages</a></li>
<li><a href="/method/langpack.getLanguage">langpack.getLanguage</a></li>
</ul>
<p>Other methods will result in an error: <a href="/api/errors#401-unauthorized"><strong>401 UNAUTHORIZED</strong></a>.</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="https://twitter.com/telegram" target="_blank" data-track="Follow/Twitter" onclick="trackDlClick(this, event)">Twitter</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>