What it means
Telegram chats come in two discoverability modes. A public supergroup or channel has a username, so anyone can find it and anyone can resolve t.me/somechannel into a peer. A private one has no username, and the only way to reference it from outside is an invite link.
The link looks like https://t.me/+AbCdEfGhIjKlMnOp, or in the older form https://t.me/joinchat/AbCdEfGhIjKlMnOp. The trailing token is the invite link hash, an opaque base64url-style string. It is not derived from the chat ID and you cannot compute one; it is issued by Telegram when an admin creates the link, and it is the entire credential.
Two API methods consume it. messages.checkChatInvite(hash) inspects the link without joining, and messages.importChatInvite(hash) actually joins. The distinction matters more than it sounds, because joining is expensive in rate-limit terms and checking is cheap.
Check before you join
checkChatInvite returns one of three shapes, and each tells you something different:
chatInvite: you are not a member. You get the title, the participant count, the photo and a small sample of participants. This is the preview a Telegram client shows you before the Join button.chatInviteAlready: you are already in. The response carries the chat itself, which conveniently gives you a usable peer with an access hash for free.chatInvitePeek: temporary read access with an expiry, which some links grant so a person can look inside before committing.
The operational value is filtering. Given a list of 400 collected invite links, checking them costs far less than joining them, and it lets you discard the dead ones, skip the chats you are already in, and rank the rest by member count before you spend a single join. Teams that skip this step burn their join budget on expired links and then wonder why the account is sitting on a multi-hour flood wait.
What an invite link actually carries
On the admin side, a link is not just a string. The chatInviteExported constructor carries the link itself plus the metadata that governs it: admin_id for who created it, date, an optional title so humans can tell links apart, expire_date, usage_limit, the running usage count, and flags for revoked, permanent and request_needed.
Every chat has one primary link, and revoking it immediately generates a replacement. Beyond that, admins can create as many additional links as they want, each with its own expiry, cap and name. Each admin only sees and manages their own set.
The Bot API exposes the same model with different names: createChatInviteLink, editChatInviteLink, revokeChatInviteLink, and a ChatInviteLink object with member_limit, creates_join_request, name, and pending_join_request_count. A bot can only edit or revoke links it created itself.
The attribution trick
Here is the feature almost nobody uses, and it turns a Telegram community from an unmeasurable blob into a real acquisition channel.
Because a chat can have unlimited named invite links, you can mint one per source: one for the website footer, one for the newsletter, one for each paid campaign, one per partner. When someone joins, Telegram tells you which link they used. Over the Bot API that arrives on the chat_member update as an invite_link object containing the name you gave it. For approval-gated links, the same information reaches you on the chat_join_request update before you decide whether to approve.
That is per-source join attribution with no tracking pixel, no redirect, and no cookie. Wire the update into your CRM and a new community member arrives already tagged with the campaign that produced them.
Joining is the expensive part
Importing invite hashes at volume is one of the fastest ways to get an account restricted, and it is worth being explicit about why.
Joining is a strong behavioural signal. Real humans join a few chats a week. An account joining dozens of private groups in an hour matches the profile of scraping and mass-promotion tooling, which is exactly what Telegram's abuse systems are tuned to catch. The response escalates from short flood waits on importChatInvite to waits measured in hours.
There is also a hard ceiling that has nothing to do with pacing. An account can belong to 500 channels and supergroups, or 1000 with Telegram Premium. Cross it and every further join fails with CHANNELS_TOO_MUCH regardless of how slowly you go. Any system that joins groups continuously needs a leave policy, not just a join policy.
Why it matters
For community operators, invite links are the membership funnel: expiry and usage caps are the access control, approval gates are the spam filter, and named links are the analytics. Handled well, a private Telegram community becomes something you can grow deliberately.
For anyone doing research or lead generation on Telegram, invite hashes are the entry point to every group that is not publicly listed, which is most of the interesting ones. Handling them carefully, checking before joining, pacing imports, and rotating across accounts, is the difference between a research pipeline that runs for months and one that burns three phone numbers in a week.
Common mistakes
- Parsing the hash with a naive split. Links arrive with tracking parameters, trailing punctuation, and both the
+andjoinchat/forms. Normalise properly or you will generate a stream ofINVITE_HASH_INVALID. - Treating INVITE_REQUEST_SENT as an error. It is a success with a pending state. Storing it as a failure means you never notice when the admin approves.
- Joining to find out whether the link works.
checkChatInviteanswers that question for a fraction of the cost. - Ignoring the 500-channel ceiling. Without a leave policy every long-running account eventually stops being able to join anything.
- Publishing a link you meant to be private. There is no per-person binding. Use single-use links with short expiries for anything sensitive.
- Using one link for every campaign. You are throwing away free attribution that Telegram hands you on the membership update.
Related concepts
- Supergroup: the chat type most invite links point at.
- Access hash: what you get back once the join succeeds and the chat becomes referenceable.
- Flood wait: the thing that punishes aggressive joining.
- Peer ID: how the joined chat is identified afterwards.
- Telegram Bot API: the admin-side methods for creating and revoking links.
- Webhook: how join events reach your CRM in real time.
How Pinlyx handles it
Pinlyx normalises every inbound link form, both t.me/+ and the legacy joinchat path, and validates with checkChatInvite before any account spends a join on it. Joins are paced per account, tracked against the channel-membership ceiling, and paused automatically when a FLOOD_WAIT comes back from importChatInvite. Pending join requests are stored as their own state rather than as failures, so an approval that lands three days later still resolves to the right record. Named invite links flow through to contact attribution, so a member who joined from a campaign link arrives in the Telegram CRM already tagged with their source.