Transports

Enables the delivery of encrypted containers together with the external header (hereinafter, Payload) from client to server and back. Multiple transport protocols are defined:

The URI format for connecting to the WebSocket and HTTP endpoints is the following:

TCP

The TCP transport is implemented simply by sending the payloads generated by the chosen MTProto transport over a plain TCP socket on ports 80, 443, 5222 or other (a different port number may be returned by help.getConfig).
Note that if the this_port_only dcOption flag is set, clients must use only the specified port, without trying any other port.
Also note that if the force_try_ipv6 config flag is set, clients must prioritize IPv6 over IPv4 for all MTProto transports, even if an IPv4 connection is available.

Framing is managed by the chosen MTProto transport protocol.

There are no implicit acknowledgments for the TCP transport: all messages must be acknowledged explicitly. Most frequently, acknowledgments are placed in a container with the next query or response if it is transmitted in short order. For example, this is almost always the case for client messages containing RPC queries: the acknowledgment normally arrives with the RPC response.

WebSocket

Implementation of the WebSocket transport is pretty much the same as with TCP: a WebSocket connection is established to the chosen MTProto server over port 80 using the specified URI format.

Note: a Sec-WebSocket-Protocol: binary header must be present in the handshake payload.

Framing of payloads is still managed by the chosen MTProto transport protocol, not by WebSocket messages: the length of MTProto payloads is defined by the MTProto transport protocol, not by the length of the single WebSocket messages. This simply means that all data received and sent through WebSocket messages is to be treated as a single duplex stream of bytes, just like with TCP.

When using the WebSocket transport, transport obfuscation is required. Transport errors are transmitted the usual way, as with TCP. The close code of WebSockets will always be 1000 (normal closure), regardless of the actual exit status. In all cases, the description string will be a decimal encoded real error code (which may be forward/back-padded with whitespaces for constant length) and can be safely ignored.

Example implementation: MadelineProto.

WebSocket over HTTPS

To establish a WebSocket connection over HTTPS, simply use the TLS URI format. The rest is the same as with plain WebSockets.

Note: a Sec-WebSocket-Protocol: binary header must be present in the handshake payload.

HTTP

Note: when implementing browser clients, WebSocket transport is recommended instead of HTTP, thanks to its full-duplex stream logic similar to TCP's; this removes the need for HTTP long polling and eventual delays while relaying RPC replies.

Implemented over HTTP/1.1 (with keepalive) running over the traditional TCP Port 80. HTTPS can also be used.

Message framing is not managed by MTProto transport protocols; it is instead handled by the HTTP protocol itself. Transport errors are also not transmitted the usual way, instead they are simply returned as normal HTTP status codes.

An HTTP connection is attached to a session (or rather, to session + key identifier) specified in the most recent user query received; normally, the session is the same in all queries, but crafty HTTP proxies may corrupt that. A server may not return a message into an HTTP connection unless it belongs to the same session, and unless it is the server's turn (an HTTP request had been received from the client to which a response has not been sent yet).

The overall arrangement is as follows. The client opens one or more keepalive HTTP or HTTPS connections to the server. If one or more messages need to be sent, they are made into a payload which is followed by a POST request to the URL/api to which the payload is transmitted as data. In addition, Content-Length, Keepalive, and Host are valid HTTP headers.

Having received the query, the server may either wait a little while (if the query requires a response following a short timeout) or immediately return a dummy response (only acknowledging the receipt of the container). In any case, the response may contain any number of messages. The server may at the same time send out any other messages it might be holding for the session.

In addition, there exists a special long poll RPC query (valid for HTTP connections only) which transmits maximum timeout T. If the server has messages for the session, they are returned immediately; otherwise, a wait state is entered until such time as the server has a message for the client or T seconds have elapsed. If no events occur in the span of T seconds, a dummy response is returned (special message).

If a server needs to send a message to a client, it checks for an HTTP connection that belongs to the required session and is in the “answering an HTTP request” state (including long poll) whereupon the message is added to the response container for the connection and sent to the user. In a typical case, there is some additional wait time (50 milliseconds) against the eventuality that the server will soon have more messages for the session.

If no suitable HTTP connection is available, the messages are placed in the current session's send queue. However, they find their way there anyway until receipt is explicitly confirmed by the client. For all protocols, the client must return an explicit acknowledgment within a reasonable time (it can be added to a container for the following request).

Important: if the acknowledgment fails to arrive on time, the message can be resent (possibly, in a different container). The parties must autonomously be ready for this and must store the identifiers of the most recent messages received (and ignore such duplicates rather than repeat actions). In order not to have the identifiers stored forever, there exist special garbage collection messages that take advantage of message identifier monotonicity.

If the send queue overflows or if messages stay in the queue for over 10 minutes, the server forgets them. This may happen even faster, if the server is running out of buffer space (for example, because of serious network issues resulting in a large number of connections becoming severed).

HTTPS

To establish a connection over HTTPS, simply use the TLS URI format. The rest is the same as with plain HTTP.

URI format

The URI format that must be used when connecting to the plain WebSocket and HTTP endpoints is the following:

http://X.X.X.X:80/api(w)(s)

The following URI may also be used only for HTTP and secure WebSocket endpoints (not usable for plain WebSocket connections):

http://(name)(-1).web.tlgr.org:80/api(w)(s)(_test)

The w flag is added when CORS headers are required in order to connect from a browser.
The s flag enables the WebSocket API.
The name placeholder in the domain version specifies the DC ID to connect to:

  • pluto => DC 1
  • venus => DC 2
  • aurora => DC 3
  • vesta => DC 4
  • flora => DC 5

-1 can be appended to the DC name to raise the maximum limit of simultaneous requests per hostname.
The _test flag, when connecting to the domain version of the URL, specifies that connection to the test DCs must be made, instead.

TLS URI format

When connecting to the HTTPS and WSS endpoints, only the domain name URI can be used over port 443:

https://(name)(-1).web.tlgr.org:443/api(w)(s)(_test)

See the URI format for an explanation of the placeholders.

Example implementations: tdlib, MadelineProto (client side), MTProxy (server side).