Skip to main content
Telegram search reads the messages DarknetSearch collects from the cybercrime Telegram channels it tracks. You send a query such as acme.com. The matching messages come back in the same response, newest first, each with a text excerpt, its channel, its date, the links it contains and the name of any attached file. This is an expert search: one indexed source, searched on its own terms. The Telegram source saves every search for your organization and returns its search_history_id. Use that ID to read more pages and to export the results as a file. To watch a term continuously instead of searching on demand, create a monitor on the Telegram source.

Availability and cost

Availability: Telegram/Discord Monitoring. The same plan feature covers Discord. Plans and quotas lists what each plan includes. Cost: no metered allowance. As with every call made with an API key, each call that returns 2xx counts once against your monthly API Calls allowance. See Rate limits. Without the feature, or when your license is not active, every endpoint on this page returns 403:
No call on this page draws a metered allowance, so a 429 here always comes from the per-second rate limit or the API Calls allowance. Errors explains each body. telegram-search-create runs the search and returns the first page of matches.
Scope a search to channels and a date range:

Query syntax

Matching is case-insensitive. A plain word also matches longer words that start with it, so acme finds acmecorp. Three rules shape a query:
  • AND binds before OR. acme.com AND combo OR credentials reads as (acme.com AND combo) OR credentials. Parentheses do not group terms, so leave them out and repeat the shared term: acme.com AND combo OR acme.com AND credentials.
  • Ten terms at most. A longer query returns 400.
  • Symbol terms need length. A term with symbols needs at least 3 characters besides them, 4 if it contains one * or ?, and 5 if it contains more.
A query the source cannot run returns 400 with the reason after Invalid search query::
The other reasons are a fuzzy distance above 5, a fuzzy phrase without a created: range or channel_ids, a symbol term that is too short, and a date filter in any form other than the two created: formats.

What comes back

  • total — messages that match. Treat it as approximate when total_is_estimate is true.
  • total_is_estimate — true when the exact count took too long. total is then the database’s estimate, or the number of rows read so far when no estimate is available.
  • channels_matched — distinct channels with a match. It reads 0 when more than 10,000 messages match or when total is an estimate.
  • page, page_size, total_pages — where you are in the result set.
  • query_info — how the source read your query. parsed_query.terms lists each term with its operator (AND or OR, how it joins the term before), negated, is_phrase and fuzzy_distance. Check it when a query returns less than you expect.
  • search_history_id — the ID of the saved search. Use it to read more pages and to export.
  • warning — set when more than 10,000 messages match, with suggestions to narrow the query. Otherwise null.
Each item in results is one message:
  • message_id — the message’s ID in its Telegram channel.
  • channel_id — the channel’s id in telegram-channels. Send it in channel_ids to search that channel again.
  • channel_username — the channel’s username or link, or null.
  • user_id — the source’s internal ID for the sender, or null.
  • text_preview — an excerpt about twice context_chars wide that starts about 60 characters before the first match. ... marks trimmed text. When no term appears literally in the message, it is the start of the message.
  • date — when the message was posted, as an ISO 8601 timestamp.
  • has_media, media_type, file_name — whether the message carries an attachment, its type and its file name.
  • links — the URLs in the message, or null.
  • channel_count, channels_list — always null.

Read more pages

telegram-search-history-results/{history_id} returns another page of a saved search. Pass the search_history_id in the path.
  • page is 1-based. page_size defaults to 10, max 100.
  • The call runs the saved search again with its saved query, channels, context_chars and unique_only, so it reflects messages collected since. Each page and page_size pair is then cached for 5 minutes, so paging back and forth inside that window stays consistent.
  • The response has the same shape as the search. search_history_id and warning are null, and query_info adds a note.
Calling telegram-search-create again with a higher page also works, but it saves a new search each time.

Export the results

telegram-search-history-export/{history_id} runs a saved search again and returns up to 10,000 matching messages as a file.
Leave format out for CSV. format=json returns JSON. format=csv, format=xml and format=pdf return 404 with {"detail": "Not found."} on this endpoint. For XML or PDF, create the export through the export service with the TelegramSearch catalog entry, passing the search_history_id as history_id.
  • CSV columns: Message ID, Channel, Channel ID, Date, Message Preview, Has Media, Media Type, File Name, Links.
  • JSON: an array of objects with message_id, channel, channel_id, date, text_preview, has_media, media_type, file_name and links.
  • The export does not apply unique_only. It returns every matching message, duplicates included.

List saved searches

telegram-search-history lists your organization’s saved Telegram searches, newest first.
  • page is 1-based. page_size defaults to 20, max 200.
  • The response holds items, total, page, page_size and total_pages.
  • Each item carries id (the history_id for the results and export calls), query, parsed_query, channel_ids, context_chars, total_matches, channels_matched, searched_at and execution_time_ms.

Channels and categories

telegram-channels lists the tracked channels. The list is the same for every organization.
The response holds items, total, page, page_size and total_pages. Each channel carries id, channel_id, username, title, description, category_id, category_name, is_active, is_private, requires_invite, last_scraped_at, total_messages_scraped and created_at.
Send the channel id in channel_ids. channel_id on a channel item is Telegram’s own channel ID and can be null. The channel_id on a search result is the channel id.
telegram-channels-categories returns every category in one response, with no paging: items and total. Each category carries id, category_name, category_description, channel_count and created_at. Pass its id as category_id.

Suggest a channel

telegram-channels-suggestions-create proposes a channel for collection. The DarknetSearch team reviews each suggestion.
channel_url is required. suggested_category and reason are optional. The call returns 201 with the suggestion: id, channel_url, suggested_category, reason, status (pending), organization_id and created_at.

Errors

Endpoints