Skip to content

Get Media ​

GET /media/{telegramId}/{chatId}/{messageId}/{variant}/{signature}.{ext}

Telegram media has no public URL. So whenever Zate gives you an image, video, sticker, document, or profile photo, whether from Get Channel Messages or the webhook, it comes as a link to this endpoint.

You never need to build the link yourself. Just use the url or thumbnail Zate gives you as is.

Endpoint Details ​

  • Base URL: https://api-zate.azickri.com
  • Headers: none, the link is already signed
  • Streaming: supports the Range header, so videos play right away and can be seeked

Parameters ​

Every part of the path is filled in by Zate. This table is just for the curious.

ParameterInDescription
telegramIdpathThe Zate session id that has access to the media.
chatIdpathID of the chat the media lives in, like -1001234567890.
messageIdpathMessage ID. For profile photos, it holds the photo ID.
variantpathphoto (largest image size), thumb (thumbnail), file (video, sticker, or document), or profile (small profile photo).
signaturepathSignature that makes the link impossible to guess or alter.
extpathFile extension, like jpg, mp4, or webp.
RangeheaderOptional. For example bytes=0-1048575 for the first 1 MB.

Usage Examples ​

html
<!-- Images and thumbnails -->
<img src="https://api-zate.azickri.com/media/68b3f0a2c1d4e5f6a7b8c9d0/-1001234567890/181/photo/Xk3d9QmPz0aB1cD2eF3gH4.jpg" alt="" />

<!-- Video, seekable right away -->
<video
  controls
  poster="https://api-zate.azickri.com/media/68b3f0a2c1d4e5f6a7b8c9d0/-1001234567890/180/thumb/Gh9iJk0lMn1oPq2rSt3uVw.jpg"
  src="https://api-zate.azickri.com/media/68b3f0a2c1d4e5f6a7b8c9d0/-1001234567890/180/file/Pq4rSt5uVw6xYz7aBc8dEf.mp4"
></video>
bash
# Download the whole file
curl -o image.jpg "https://api-zate.azickri.com/media/68b3f0a2c1d4e5f6a7b8c9d0/-1001234567890/181/photo/Xk3d9QmPz0aB1cD2eF3gH4.jpg"

# Just the first 1 MB
curl -r 0-1048575 -o part.mp4 "https://api-zate.azickri.com/media/68b3f0a2c1d4e5f6a7b8c9d0/-1001234567890/180/file/Pq4rSt5uVw6xYz7aBc8dEf.mp4"
javascript
const url = 'https://api-zate.azickri.com/media/68b3f0a2c1d4e5f6a7b8c9d0/-1001234567890/181/photo/Xk3d9QmPz0aB1cD2eF3gH4.jpg';

const response = await fetch(url);
if (response.status === 503) {
  const wait = Number(response.headers.get('Retry-After'));
  console.log(`Telegram asks to wait ${wait} seconds`);
}

const buffer = Buffer.from(await response.arrayBuffer());

Response ​

On success the body is the file itself, not JSON:

StatusWhen
200The whole file, for a request without Range.
206Part of the file, matching the Range you asked for. Comes with a Content-Range header.
Response headerDescription
Content-TypeFile type, like image/jpeg or video/mp4.
Content-LengthSize of the part being sent, in bytes.
Accept-RangesAlways bytes.
Cache-Controlpublic, max-age=86400, so browsers may keep it for up to a day.

On failure, the error has the same shape as every other endpoint:

json
// The link was tampered with
{
  "statusCode": 400,
  "message": "telegramId must be a mongodb id"
}
json
// Signature doesn't match, or the message was deleted
{
  "statusCode": 404,
  "message": "media not found"
}
json
// Range outside the file size
{
  "statusCode": 416,
  "message": "range not satisfiable"
}
json
// The session that owns the link isn't connected
{
  "statusCode": 500,
  "message": "session not connected"
}
json
// Comes with a Retry-After header
{
  "statusCode": 503,
  "message": "telegram asked to wait 120s"
}

How It Works ​

  • Never downloaded whole. Zate fetches the file from Telegram in 512 KB chunks, only when the viewer actually reaches that part. A 2 GB video only "costs" the part that's watched, and closing or seeking the video stops the fetching right away.
  • Fetched chunks are cached for 1 hour after they were last opened. Replaying or seeking back doesn't go to Telegram again.
  • The session must be connected, unless every requested chunk is still in the cache.
  • Image sizes: photo is the largest size (up to 2560 pixels), an image thumb is about 800 pixels, and a video thumb is 320 pixels, the size Telegram keeps.
  • A new profile photo = a new link, so browsers never show the old photo from their cache.

These links are public

Anyone holding the link can open the media without headers, including media from private channels. Treat links to private channel media as sensitive and don't put them on public pages.