Skip to main content

Retrieve and Search Telegram Posts with the API

There are two starting points: list publications of a known channel, or search post text across channels. Use the channel's internal ID for channel-specific requests.

Can I monitor brand mentions in Telegram?

Use the Telemetr.io post search API to find a brand name or phrase in indexed Telegram channel posts. GET /v1/search/messages returns matching posts and supports phrase queries, excluded terms, date ranges and cursor pagination. For example, search for a brand, review the matching publications and save their IDs for a later monitoring run.

QuestionAnswer
What data do I get?Post text, publication date, views and the channel's internal ID. Request return_short_info=true to include basic channel information.
Which key do I need?An Advanced or Team Credits API key, or a Subscription API key with message-search access enabled. See plans and limits.
Is every page free after the first search?No. Each page is another API request. Credits charges and Subscription allowances are explained under billing.
Will it find every mention of a brand?Results depend on indexed posts, the query and the history accessible to your key. A name match does not identify a unique company; review ambiguous matches and search relevant aliases separately.

The Python example below searches a fixed seven-day window and prints matching posts as JSON Lines. The frequently asked questions cover phrase matching, exclusions, pagination and recurring searches.

Read a channel's publications

curl --fail-with-body --get "https://api.tlmtr.io/v1/messages/channel" \
-H "x-api-key: $TELEMETRIO_API_KEY" \
--data-urlencode "internal_id=$CHANNEL_ID"

The response includes messages, related chats and an optional cursor. Pass a returned cursor unchanged on the next request. Continue until no cursor is returned. Use /v1/messages/group for group messages.

The from_date and to_date filters on message-list endpoints are Unix timestamps in seconds. History is limited by the key's access. See the endpoint reference for the exact fields of channel and group messages.

Retrieve one message or its views

TaskEndpointRequired IDs
Channel message/v1/messages/by_idinternal_id, message_id
Group message/v1/messages/group_by_idinternal_id, message_id
Message views history/v1/messages/viewsinternal_id, message_id

Message IDs identify a message within its chat. Keep the pair of chat and message IDs rather than treating a message ID as globally unique.

Search post text

Advanced and Team credits access includes post search. Subscription API search access is configured separately.

curl --fail-with-body --get "https://api.tlmtr.io/v1/search/messages" \
-H "x-api-key: $TELEMETRIO_API_KEY" \
--data-urlencode "term=bitcoin" \
--data-urlencode "exclude_terms=casino,advertisement" \
--data-urlencode "return_short_info=true"

Use quotes inside term for phrase matching. exclude_terms is a comma-separated string of terms to exclude from post text; empty entries are ignored. Keep exclusions, filters, dates and sorting unchanged when following the response's cursor.

The response contains messages, count, related chats when requested, and an optional cursor. Sorting supports date, relevance and views; see the reference for exact parameters and defaults.

Explicit post-search date ranges require both date_from and date_to; the effective range is limited by the key's history access and the present time. Date parameter names differ from the channel-message list, so do not reuse one endpoint's parameter object for another.

Python example: monitor a brand name

This example uses Python 3.9+ and its standard library, with no extra packages. Save it as search_brand_mentions.py, set TELEMETRIO_API_KEY in your environment, and replace the illustrative Acme phrase in term with your brand. Get your key through the quickstart.

Run python3 search_brand_mentions.py > mentions.jsonl. Progress and errors go to stderr, so the output file contains only one JSON object per matching post.

import json
import os
import sys
from datetime import datetime, timedelta, timezone
from urllib.error import HTTPError
from urllib.parse import urlencode
from urllib.request import Request, urlopen

api_key = os.environ["TELEMETRIO_API_KEY"]
max_pages = 3 # Each page is a separate API request.
window_end = datetime.now(timezone.utc)
params = {
"term": '"Acme"',
"date_from": (window_end - timedelta(days=7)).isoformat(),
"date_to": window_end.isoformat(),
"sort": "date",
"return_short_info": "true",
}

for page_number in range(1, max_pages + 1):
request = Request(
"https://api.tlmtr.io/v1/search/messages?" + urlencode(params),
headers={"x-api-key": api_key, "Accept": "application/json"},
)
try:
with urlopen(request, timeout=30) as response:
result = json.load(response)
except HTTPError as error:
raise SystemExit(
f"API returned HTTP {error.code} on page {page_number}. "
"Check the authentication and errors guide before retrying."
) from None

channels = {chat["internal_id"]: chat for chat in result["chats"]}
for post in result["messages"]:
print(json.dumps({
"channel_internal_id": post["peer_id"],
"channel_title": channels.get(post["peer_id"], {}).get("title"),
"message_id": post["message_id"],
"date": post["date"],
"views": post["views"],
"text": post["text"],
}, ensure_ascii=False))

cursor = result.get("cursor")
if not cursor:
print(f"Finished after {page_number} page(s).", file=sys.stderr)
break
params["cursor"] = cursor # Keep the phrase, dates and sort unchanged.
else:
print("Stopped at the page limit; more results are available.", file=sys.stderr)

An illustrative output line, not a live search result:

{"channel_internal_id":"example-channel-id","channel_title":"Example channel","message_id":42,"date":"2026-09-10T12:00:00Z","views":1250,"text":"Acme announces a product update."}

channel_internal_id is the response's peer_id, not a Telegram numeric ID. channel_title is null if the response has no matching chat metadata. No matching posts produces an empty output file. If a later page fails, earlier lines remain in the file: treat that run as incomplete.

For repeated monitoring, save the pair (channel_internal_id, message_id) and deduplicate across overlapping search windows. Keep the time window fixed while following a cursor. Live results can change between requests; this example does not guarantee exhaustive or exactly-once delivery. It performs no automatic retries. Review errors and access failures before rerunning a request that may consume credits.

Billing

Credits search uses an inclusive request price and can additionally charge for a search term first used in the current billing period. Subscription search counts calls and distinct terms against separate configured allowances. Repeating a term does not make all subsequent calls free.

For stable handling of failures and pagination, see integration essentials.

Frequently asked questions

How do I search for an exact phrase or brand name?

Put double quotes around the phrase inside the term parameter, such as term="Acme Labs". With curl, use --data-urlencode 'term="Acme Labs"' to preserve the quotes and spaces. A phrase match finds that wording; search relevant brand aliases separately and review ambiguous names. See the post search parameters.

How do I exclude unwanted words from Telegram post search?

Pass a comma-separated string in exclude_terms, for example exclude_terms=casino,advertisement. Exclusions use the search service's text matching on post text; they are not a literal substring filter and do not check link fields. Keep the same exclusions when requesting another page. The curl example shows how to combine a search term with exclusions.

How do I retrieve the next page of search results?

Send the response's cursor unchanged as the next request's cursor parameter, retaining the original phrase, exclusions, filters, dates and sort order. Stop when the response has no cursor; each page is a separate API request with its own applicable charge or usage count. The Python example follows cursors and caps the run at three requests.

Why does the API not find every mention of my brand?

Telemetr.io searches indexed Telegram channel posts within the history accessible to your API key. Check the search phrase and aliases, excluded terms, channel or country filters, and the date range; a narrow query can omit relevant posts. An empty result does not establish that no one mentioned the brand on Telegram. See API access and history limits and the search parameters.

How do I avoid duplicate posts in regular monitoring?

Persist the pair (peer_id, message_id) for each result; the Python example writes peer_id as channel_internal_id. When repeating searches over overlapping time windows, use that pair as the stored record's unique key, since a message ID alone is not globally unique. Update an existing record if you want to retain changed text or view counts, and emit a new-post notification only for a previously unseen pair. See identifier and pagination conventions.