Skip to content

Telegram API

The TrueScrape Telegram API exposes 3 public endpoints covering Channel, Channel posts and Post. Every call is a GET against public, logged-out pages and returns the same unified schema as every other platform here. Calls cost 1 credit each. A cache hit is free, and a failed or empty response is never charged.

Endpoints

EndpointReturnsCreditsCacheableBatchable
/v1/telegram/channelChannel1yesyes
/v1/telegram/channel-postsChannel posts1yesyes
/v1/telegram/postPost1yesyes

Reference

GET/v1/telegram/channel1 creditcacheablebatchable

Channel

Public Telegram channel or group metadata including its name, description, avatar, verification status, subscriber or member count, and public media counters. The subscriber or member count is exact, read from the channel's t.me page, and falls back to the rounded preview value ("9.66M") when that page cannot be read. The media counters in raw.counters are Telegram's rounded display text. Uses Telegram's public web preview and does not use a logged-in Telegram account, so private channels, invite-only groups and user accounts are not covered. An old username still resolves to the channel that took it over, so handle here is the header username and may differ from the one inside a post id, so join on a post id, never on the handle.

ParameterTypeRequiredDescription
handlestringyesPublic channel or group username: @telegram, telegram, or https://t.me/telegram

Also accepts cache_max_age (a hit costs 0 credits) and include_raw (returns the untouched upstream payload under raw).

Returns one Creator.

Fields
FieldTypePresentDescription
platformone of 32 stringsalways
idstringalwaysThe platform's own id for the account, such as a channel id or a numeric user id, always as a string.
handlestring | nullalwaysThe account handle without the leading @. Null when the platform has no handles.
displayNamestring | nullalways
biostring | nullalways
avatarUrlstring | nullalways
bannerUrlstring | nullalways
urlstring | nullalways
verifiedboolean | nullalwaysWhether the platform shows a verification badge on the account. Null where the platform has no public badge or does not expose it.
followerCountnumber | nullalwaysFollowers, subscribers, or the platform's nearest equivalent. Null when the account hides the count or the platform does not expose it.
followingCountnumber | nullalways
postCountnumber | nullalwaysPosts, videos, tracks, repositories, or the platform's nearest equivalent that the account has published.
viewCountnumber | nullalwaysLifetime views across the account, where the platform exposes a total.
likeCountnumber | nullmay be absentTotal likes received across all of the creator's posts. Distinct from `viewCount`. Absent when the platform does not expose it.
isPrivateboolean | nullalways
isBusinessboolean | nullalwaysWhether the platform classifies the account as a business or organisation rather than a person or creator. Null where the platform draws no such line or does not expose it. On Facebook every Page counts, including Pages for public figures.
categorystring | nullalwaysA label the platform attaches to the account, such as a business category, a genre or an account type. What it holds varies by platform.
locationstring | nullalwaysLocation as the platform shows it: a city, a country, a region code or an address, depending on the platform.
externalLinksstring[]alwaysLinks the account lists on its profile, such as a website or other social accounts.
createdAtstring | nullalwaysWhen the account was created. Usually an ISO 8601 timestamp; some platforms expose only the date as shown on the profile.
fetchedAtstringalwaysWhen this record was fetched from the platform, as an ISO 8601 timestamp. A cached response keeps the time of the original fetch.
curl
curl "$API/v1/telegram/channel?handle=%40mkbhd&cache_max_age=7d" \
  -H "x-api-key: $KEY"
TypeScript
const query = new URLSearchParams({
  handle: '@mkbhd',
  cache_max_age: '7d',
});

const response = await fetch(`${API}/v1/telegram/channel?${query}`, {
  headers: { 'x-api-key': KEY },
});

const body = await response.json();
if (!body.success) throw new Error(body.error.code);

// 1 credit, 0 on a cache hit
console.log(body.data, body.meta.creditsCharged);
Python
Python
import os, httpx

r = httpx.get(
    f"{os.environ['API']}/v1/telegram/channel",
    params={
        "handle": "@mkbhd",
        "cache_max_age": "7d",
    },
    headers={"x-api-key": os.environ["KEY"]},
    timeout=30,
)

body = r.json()
if not body["success"]:
    raise RuntimeError(body["error"]["code"])

print(body["data"], body["meta"]["creditsCharged"])
Response codes
200Success
400invalid_request. Not charged
401missing_api_key / invalid_api_key / revoked_api_key. Never a billing error
402insufficient_credits. The key is valid, the balance is not
429daily_cap_exceeded or upstream_rate_limited. Not charged
501not_configured. This deployment is not set up to serve this endpoint. Not charged.
502upstream_blocked / upstream_schema_drift. Not charged
504upstream_timeout. Not charged
Try it here
GET/v1/telegram/channel
Open the full playground
GET/v1/telegram/channel-posts1 creditcacheablebatchable

Channel posts

One public web-preview page of Telegram posts with text, publish date, views, reactions when exposed, forwards, media (photos and the playable video file), and link previews. Twenty posts per page, newest first. Pass the returned cursor to fetch the previous page. Empty and terminal pages are not charged. viewCount is Telegram's own rounded display value ("1.37M" → 1370000), not an exact count; the original text is in raw.messages[].viewsText. likeCount totals every public reaction, paid stars included, from Telegram's rounded display values, and is null when a post shows no reactions. Each reaction, the forward source and the link preview are under raw. A post id carries the CANONICAL username of the channel, which differs from the one you asked for when an old username still resolves to it. Join on id, not on the handle you passed.

ParameterTypeRequiredDescription
handlestringyesPublic channel or group username: @telegram, telegram, or https://t.me/telegram
cursorstringnopagination.cursor from a previous response

Also accepts cache_max_age (a hit costs 0 credits) and include_raw (returns the untouched upstream payload under raw).

Returns a list of Post in data.items.

Fields
FieldTypePresentDescription
platformone of 32 stringsalways
idstringalways
typevideo | short | image | carousel | text | live | story | reel | audio | album | episode | unknownalwaysWhat kind of post this is. `short` and `reel` are short-form video formats, `live` is a live stream or a recording of one, `carousel` holds several images or videos, `audio` is a music track, `album` is an album, `episode` is a podcast episode, and `unknown` covers anything else.
urlstring | nullalways
titlestring | nullalways
textstring | nullalwaysThe post's text: a caption, a description or the message body.
authorIdstring | nullalways
authorHandlestring | nullalways
authorNamestring | nullalways
thumbnailUrlstring | nullalways
mediaUrlsstring[]always
durationSecondsnumber | nullalways
viewCountnumber | nullalwaysViews. Null means the platform did not expose a count, which is not the same as zero.
likeCountnumber | nullalwaysLikes, or the platform's nearest equivalent. Null means not exposed, not zero.
commentCountnumber | nullalwaysComments. Null means not exposed, not zero.
shareCountnumber | nullalwaysShares, reposts, or the platform's nearest equivalent. Null means not exposed, not zero.
hashtagsstring[]alwaysHashtags or the platform's own topic tags, without the leading #.
mentionsstring[]alwaysHandles mentioned in the post text, without the leading @.
taggedUsersstring[]may be absentUsernames tagged in the media itself, as distinct from `mentions`, which come from the caption text. Absent when the platform does not report tags; an empty array means it reports none.
isSponsoredboolean | nullalwaysWhether the platform labels the post as an ad, promoted content or a paid partnership.
publishedAtstring | nullalwaysWhen the post was published. Usually an ISO 8601 timestamp; some platforms expose only a date or relative text such as "3 days ago".
fetchedAtstringalwaysWhen this record was fetched from the platform, as an ISO 8601 timestamp. A cached response keeps the time of the original fetch.
curl
curl "$API/v1/telegram/channel-posts?handle=%40mkbhd&cache_max_age=7d" \
  -H "x-api-key: $KEY"
TypeScript
const query = new URLSearchParams({
  handle: '@mkbhd',
  cache_max_age: '7d',
});

const response = await fetch(`${API}/v1/telegram/channel-posts?${query}`, {
  headers: { 'x-api-key': KEY },
});

const body = await response.json();
if (!body.success) throw new Error(body.error.code);

// 1 credit, 0 on a cache hit
console.log(body.data, body.meta.creditsCharged);
Python
Python
import os, httpx

r = httpx.get(
    f"{os.environ['API']}/v1/telegram/channel-posts",
    params={
        "handle": "@mkbhd",
        "cache_max_age": "7d",
    },
    headers={"x-api-key": os.environ["KEY"]},
    timeout=30,
)

body = r.json()
if not body["success"]:
    raise RuntimeError(body["error"]["code"])

print(body["data"], body["meta"]["creditsCharged"])
Response codes
200Success
400invalid_request. Not charged
401missing_api_key / invalid_api_key / revoked_api_key. Never a billing error
402insufficient_credits. The key is valid, the balance is not
429daily_cap_exceeded or upstream_rate_limited. Not charged
501not_configured. This deployment is not set up to serve this endpoint. Not charged.
502upstream_blocked / upstream_schema_drift. Not charged
504upstream_timeout. Not charged
Try it here
GET/v1/telegram/channel-posts
Open the full playground
GET/v1/telegram/post1 creditcacheablebatchable

Post

A single public Telegram post with its text, publish date, views, reactions when exposed, forward source, media (photos and the playable video file), and link preview. viewCount is Telegram's own rounded display value ("1.37M" → 1370000), not an exact count; the original text is in raw.viewsText. likeCount totals every public reaction, paid stars included, from Telegram's rounded display values, and is null when the post shows no reactions. Each reaction, the forward source and the link preview are under raw. Reads the public post embed and does not use a logged-in Telegram account.

ParameterTypeRequiredDescription
urlstringyesPost link: https://t.me/<handle>/<message id>, for example https://t.me/telegram/441

Also accepts cache_max_age (a hit costs 0 credits) and include_raw (returns the untouched upstream payload under raw).

Returns one Post.

Fields
FieldTypePresentDescription
platformone of 32 stringsalways
idstringalways
typevideo | short | image | carousel | text | live | story | reel | audio | album | episode | unknownalwaysWhat kind of post this is. `short` and `reel` are short-form video formats, `live` is a live stream or a recording of one, `carousel` holds several images or videos, `audio` is a music track, `album` is an album, `episode` is a podcast episode, and `unknown` covers anything else.
urlstring | nullalways
titlestring | nullalways
textstring | nullalwaysThe post's text: a caption, a description or the message body.
authorIdstring | nullalways
authorHandlestring | nullalways
authorNamestring | nullalways
thumbnailUrlstring | nullalways
mediaUrlsstring[]always
durationSecondsnumber | nullalways
viewCountnumber | nullalwaysViews. Null means the platform did not expose a count, which is not the same as zero.
likeCountnumber | nullalwaysLikes, or the platform's nearest equivalent. Null means not exposed, not zero.
commentCountnumber | nullalwaysComments. Null means not exposed, not zero.
shareCountnumber | nullalwaysShares, reposts, or the platform's nearest equivalent. Null means not exposed, not zero.
hashtagsstring[]alwaysHashtags or the platform's own topic tags, without the leading #.
mentionsstring[]alwaysHandles mentioned in the post text, without the leading @.
taggedUsersstring[]may be absentUsernames tagged in the media itself, as distinct from `mentions`, which come from the caption text. Absent when the platform does not report tags; an empty array means it reports none.
isSponsoredboolean | nullalwaysWhether the platform labels the post as an ad, promoted content or a paid partnership.
publishedAtstring | nullalwaysWhen the post was published. Usually an ISO 8601 timestamp; some platforms expose only a date or relative text such as "3 days ago".
fetchedAtstringalwaysWhen this record was fetched from the platform, as an ISO 8601 timestamp. A cached response keeps the time of the original fetch.
curl
curl "$API/v1/telegram/post?url=8XkPqR2nLvE&cache_max_age=7d" \
  -H "x-api-key: $KEY"
TypeScript
const query = new URLSearchParams({
  url: '8XkPqR2nLvE',
  cache_max_age: '7d',
});

const response = await fetch(`${API}/v1/telegram/post?${query}`, {
  headers: { 'x-api-key': KEY },
});

const body = await response.json();
if (!body.success) throw new Error(body.error.code);

// 1 credit, 0 on a cache hit
console.log(body.data, body.meta.creditsCharged);
Python
Python
import os, httpx

r = httpx.get(
    f"{os.environ['API']}/v1/telegram/post",
    params={
        "url": "8XkPqR2nLvE",
        "cache_max_age": "7d",
    },
    headers={"x-api-key": os.environ["KEY"]},
    timeout=30,
)

body = r.json()
if not body["success"]:
    raise RuntimeError(body["error"]["code"])

print(body["data"], body["meta"]["creditsCharged"])
Response codes
200Success
400invalid_request. Not charged
401missing_api_key / invalid_api_key / revoked_api_key. Never a billing error
402insufficient_credits. The key is valid, the balance is not
429daily_cap_exceeded or upstream_rate_limited. Not charged
501not_configured. This deployment is not set up to serve this endpoint. Not charged.
502upstream_blocked / upstream_schema_drift. Not charged
504upstream_timeout. Not charged
Try it here
GET/v1/telegram/post
Open the full playground

Questions

How much does the Telegram API cost?
Calls cost 1 credit each. Every endpoint is cacheable, and a cache hit costs nothing. A failed request and an empty result are both free, on every endpoint.
Does the Telegram API need a login or cookies?
No. Every endpoint reads public, logged-out pages only — no account, no cookies, no session. An API key identifies your own TrueScrape account and nothing else.
Can I fetch many Telegram targets in one request?
Yes. 3 of 3 are batchable: one POST to /v1/jobs/batch takes many targets and returns a job id to poll.
Can I watch Telegram endpoints for changes?
Yes, 3 of 3. A subscription polls on your schedule and fires your webhook only when the content changed; the rest carry x-subscribable: false in the spec.