Uploading and Downloading Files

When working with the API, it is sometimes necessary to send a relatively large file to the server. For example, when sending a message with a photo/video attachment or when setting the current user’s profile picture.

Uploading files

There are a number of API methods to save files. The schema of the types and methods used is presented below:

inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile;
inputFileBig#fa4f0bb5 id:long parts:int name:string md5_checksum:string = InputFile;


inputEncryptedFileUploaded id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile;
inputEncryptedFileBigUploaded id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile;

inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile;
inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile;

inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;

inputChatUploadedPhoto#94254732 file:InputFile crop:InputPhotoCrop = InputChatPhoto;


---functions---

messages.sendMedia#b8d1262b flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
messages.sendEncryptedFile peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage;

photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo;    

upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool;
upload.saveBigFilePart file_id:long file_part:int file_total_parts:int bytes:bytes = Bool;

Before transmitting the contents of the file itself, the file has to be assigned a unique 64-bit client identifier: file_id.

The file’s binary content is then split into parts. All parts must have the same size ( part_size ) and the following conditions must be met:

  • part_size % 1024 = 0 (divisible by 1KB)
  • 524288 % part_size = 0 (512KB must be evenly divisible by part_size)

The last part does not have to satisfy these conditions, provided its size is less than part_size.

Each part should have a sequence number, file_part, with a value ranging from 0 to 2,999.

After the file has been partitioned you need to choose a method for saving it on the server. Use upload.saveBigFilePart in case the full size of the file is more than 10 MB and upload.saveFilePart for smaller files.

Each call saves a portion of the data in a temporary location on the server to be used later. The storage life of each portion of data is between several minutes and several hours (depending on how busy the storage area is). After this time, the file part will become unavailable. To increase the time efficiency of a file save operation, we recommend using a call queue, so X pieces of the file are being saved at any given moment in time. Each successful operation to save a part invokes the method call to save the next part. The value of X can be tuned to achieve maximum performance.

When using one of the methods mentioned above to save file parts, one of the following data input errors may be returned:

  • FILE_PARTS_INVALID - Invalid number of parts. The value is not between 1..3000
  • FILE_PART_INVALID: The file part number is invalid. The value is not between 0 and 2,999.
  • FILE_PART_TOO_BIG: The size limit (512 KB) for the content of the file part has been exceeded
  • FILE_PART_EMPTY: The file part sent is empty
  • FILE_PART_SIZE_INVALID - 512KB cannot be evenly divided by part_size
  • FILE_PART_SIZE_CHANGED - The part size is different from the size of one of the previous parts in the same file

While the parts are being uploaded, an MD5 hash of the file contents can also be computed to be used later as the md5_checksum parameter in the inputFile constructor (since it is checked only by the server, for encrypted secret chat files it must be generated from the encrypted file).
After the entire file is successfully saved, the final method may be called and passed the generated inputFile object. In case the upload.saveBigFilePart method is used, the inputFileBig constructor must be passed, in other cases use inputFile.

The file save operation may return one of the following data input errors:

  • FILE_PARTS_INVALID: The number of file parts is invalid The value is not between 1 and 3,000.
  • FILE_PART_Х_MISSING: Part X (where X is a number) of the file is missing from storage. Try repeating the method call to resave the part.
  • MD5_CHECKSUM_INVALID: The file’s checksum did not match the md5_checksum parameter

Re-using pre-uploaded files

document#9ba29cc1 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumbs:flags.0?Vector<PhotoSize> dc_id:int attributes:Vector<DocumentAttribute> = Document;

---functions---

messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document;

For some types of documents like GIFs, messages.getDocumentByHash can be used to search for the document on Telegram servers.
The SHA256 hash of the file is computed, and it is passed along with the file's mime type and size to the method: if the file type is correct and the file is found, a document is returned.

Downloading files

There are methods available to download files which have been successfully uploaded. The schema of the types and methods used is presented below:

upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File;
upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector<FileHash> = upload.File;

storage.fileUnknown#aa963b05 = storage.FileType;
storage.fileJpeg#7efe0e = storage.FileType;
storage.fileGif#cae1aadf = storage.FileType;
storage.filePng#a4f63c0 = storage.FileType;
storage.fileMp3#528a0677 = storage.FileType;
storage.fileMov#4b09ebbc = storage.FileType;
storage.filePartial#40bc6f52 = storage.FileType;
storage.fileMp4#b3cea0e4 = storage.FileType;
storage.fileWebp#1081464c = storage.FileType;

---functions---

upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File;

Any file can be downloaded by calling upload.getFile.
The data for the input parameter of the InputFileLocation type is generated as follows:

inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation;
inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation;
inputDocumentFileLocation#bad07584 id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation;
inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation;
inputTakeoutFileLocation#29be5899 = InputFileLocation;
inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation;
inputPeerPhotoFileLocation#27d69997 flags:# big:flags.0?true peer:InputPeer volume_id:long local_id:int = InputFileLocation;
inputStickerSetThumb#dbaeae9 stickerset:InputStickerSet volume_id:long local_id:int = InputFileLocation;

inputStickerSetEmpty#ffb62b95 = InputStickerSet;
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;

inputPeerSelf#7da07ec9 = InputPeer;
inputPeerChat#179be863 chat_id:int = InputPeer;
inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer;
inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer;

photo#d07504a5 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector<PhotoSize> dc_id:int = Photo;
document#9ba29cc1 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumbs:flags.0?Vector<PhotoSize> dc_id:int attributes:Vector<DocumentAttribute> = Document;

photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;

The size of each file in bytes is available, which makes it possible to download the file in parts using the parameters offset and limit, similar to the way files are uploaded, also:

  • The parameter offset must be divisible by 1 KB.
  • 10485760 (1MB) must be divisible by limit

The file download operation may return a FILE_REFERENCE_EXPIRED error (or another error starting with FILE_REFERENCE_): in this case, the file_reference field of the input location must be refreshed.
The file download operation may return an upload.fileCdnRedirect constructor: in this case, these instructions must be followed for downloading CDN files.
The file download operation may also return one of the following data input errors:

  • FILE_ID_INVALID: The file address is invalid
  • OFFSET_INVALID: The offset value is invalid. The value is not divisible by 1 KB.
  • LIMIT_INVALID: The limit value is invalid
  • FILE_MIGRATE_X: The file is in Data Center No. X

Verifying downloaded chunks

fileHash#6242c773 offset:int limit:int hash:bytes = FileHash;

---functions---

upload.getFileHashes#c7025931 location:InputFileLocation offset:int = Vector<FileHash>;

In order to confirm the integrity of the downloaded file, clients are recommended to verify hashes for each downloaded part, as for CDN DCs.
upload.getFileHashes contain FileHash constructors. Each of these constructors contains the SHA-256 hash of a part of the file that starts with offset and takes limit bytes.

Before saving each portion of the data received from the DC into the file, the client can confirm that its hash matches the hash that was received from the master DC. If missing a hash for any file part, client developers must use the upload.getFileHashes method to obtain the missing hash.

Downloading webfiles

Remote HTTP files sent by inline bots in response to inline queries and in other places are represented by WebDocument constructors.
When forwarding such remote HTTP files, they should be sent using external InputMedia constructors.
Remote HTTP files can only be downloaded directly by the client if contained in a webDocumentNoProxy constructor: in this case, the file is deemed safe to download (this is the case for HTTPS files from certain trusted domains).

However, if the remote file is contained in a webDocument, to avoid leaking sensitive information the file must be downloaded through telegram's servers.
This can be done in a manner similar to normal files, with the difference that upload.getWebFile must be used, instead.

upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile;

storage.fileUnknown#aa963b05 = storage.FileType;
storage.fileJpeg#7efe0e = storage.FileType;
storage.fileGif#cae1aadf = storage.FileType;
storage.filePng#a4f63c0 = storage.FileType;
storage.fileMp3#528a0677 = storage.FileType;
storage.fileMov#4b09ebbc = storage.FileType;
storage.filePartial#40bc6f52 = storage.FileType;
storage.fileMp4#b3cea0e4 = storage.FileType;
storage.fileWebp#1081464c = storage.FileType;

---functions---

upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile;

The InputWebFileLocation constructor is generated as follows.

inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation;
inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation;

webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector<DocumentAttribute> = WebDocument;

inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint;

geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint;
  • inputWebFileLocation is simply generated by taking the url and access_hash fields of the webDocument constructor.
  • inputWebFileGeoPointLocation is used to download a server-generated image with the map preview from a geoPoint.
    • geo_point is generated from the lat and long parameters of the geoPoint
    • access_hash is the access hash of the geoPoint
    • w - Map width in pixels before applying scale; 16-1024
    • h - Map height in pixels before applying scale; 16-1024
    • zoom - Map zoom level; 13-20
    • scale - Map scale; 1-3

General Considerations

It is recommended that large queries (upload.getFile, upload.saveFilePart) be handled through a separate session and a separate connection, in which no methods other than these should be executed. If this is done, then data transfer will cause less interference with getting updates and other method calls.

Related articles

Handling file references

How to handle file references.