How to Check if a Number Is on Telegram (Checker API)

Published August 23, 2026 Β· UpdatedOctober 9, 2026

Telegram has over a billion users, and in many regions and communities it is the primary messaging channel. That makes "is this contact on Telegram?" a question worth answering before you build outreach, support or verification flows around it. A Telegram number checker answers it with a single, cheap API call, and a second step adds the public bio and profile photo for the accounts that exist.

This guide shows how to check a phone number, username or user ID, how the two-step userHash flow works, and how to handle the results in Python. None of these lookups requires you to log in a Telegram account.

Step 1: Get an API key

Sign up, open your Dashboard and copy an active API key. Free credits are included for testing.

Step 2: Check that the peer exists

The check-exists operation takes one peer. It accepts three forms:

  • +phone: digits with a leading plus, for example +8613800138000.
  • @username or a bare username.
  • user:<id> for a numeric Telegram user ID.
curl "https://api.opendata-api.com/api/project/telegram/check-exists?key=YOUR_API_KEY&peer=%2B8613800138000"

Write the plus sign as %2B when you build the URL by hand, otherwise it is read as a space. Passing a username is especially useful when you only have someone's Telegram handle rather than their phone number.

When the peer exists (exists=true), the response includes the numeric Telegram user id, the username when the peer has one, the display name, and a userHash. When it does not exist, exists is false and reason carries a code such as PHONE_NOT_OCCUPIED or USERNAME_NOT_OCCUPIED, which tells you whether a number or a handle was the problem.

Step 3: Fetch the bio and avatar

The userHash authorizes the two heavier lookups. It is valid for 24 hours, and calls with a missing, unknown or expired hash are rejected. You pass only the hash; no peer parameter is accepted on these operations.

# Bio ("about") text, plus numeric user id and username
curl "https://api.opendata-api.com/api/project/telegram/get-about?key=YOUR_API_KEY&userHash=USER_HASH"

# Profile photo, returned base64-encoded
curl "https://api.opendata-api.com/api/project/telegram/get-picture?key=YOUR_API_KEY&userHash=USER_HASH"

Read the results carefully:

  • An empty about means the user has no bio or hides it. It is not an error.
  • For get-picture, Telegram photos have no public URL, so the image arrives base64-encoded in the data field together with its MIME type (image/jpeg). Decode data to get the bytes.
  • pictureSet=false means the user has no photo or hides it through privacy settings.
  • If the peer turns out to be a group or channel rather than a user, get-about returns a bad-request business code instead of a bio.

A complete Python example

import base64
import requests

API_KEY = "YOUR_API_KEY"
BASE = "https://api.opendata-api.com/api/project/telegram"


def get(operation, **params):
    params["key"] = API_KEY
    resp = requests.get(f"{BASE}/{operation}", params=params, timeout=30)
    resp.raise_for_status()
    body = resp.json()
    # A reply can be wrapped more than once as {"code": ..., "data": {...}}
    while isinstance(body, dict) and "code" in body and isinstance(body.get("data"), (dict, list)):
        body = body["data"]
    return body


def telegram_profile(peer, want_photo=False):
    found = get("check-exists", peer=peer)   # requests encodes "+" for you
    if found.get("exists") is False:
        return {"peer": peer, "exists": False, "reason": found.get("reason")}

    user_hash = found.get("userHash")
    if found.get("exists") is not True or not user_hash:
        raise RuntimeError(f"unexpected reply: {found}")
    about = get("get-about", userHash=user_hash)
    profile = {
        "peer": peer,
        "exists": True,
        "username": found.get("username"),
        "about": about.get("about") or None,
    }
    if want_photo:
        picture = get("get-picture", userHash=user_hash)
        if picture.get("pictureSet") and picture.get("data"):
            profile["photo"] = base64.b64decode(picture["data"])
    return profile


print(telegram_profile("+8613800138000"))
print(telegram_profile("@some_username", want_photo=True))

Notice that the photo call is optional. Existence plus the bio often answers the question, and skipping the photo saves a request per contact.

Bulk lists and caching

There is no batch operation for Telegram, so loop over your list and keep the work small:

  1. Deduplicate and normalize the peers first. Phone numbers need the leading + and the country code.
  2. Call check-exists once per peer and store exists, reason, the user id and the userHash together with a timestamp.
  3. Call get-about and get-picture only for the peers you actually need to enrich, and only while the hash is under 24 hours old. After that, run check-exists again to get a fresh hash.
  4. Re-check on a schedule rather than on every touch, because usernames and bios can change.

Telegram compared with WhatsApp

Both messengers can be checked by number, but they are not interchangeable. Telegram also lets you look up a public username and returns a user id, while WhatsApp is number-only. If you are deciding which channel to verify first, read WhatsApp vs Telegram lookup APIs. If you need to go from checking to actually contacting someone, send and read Telegram messages in Python uses a logged-in account instead, and combining several channels is covered in the lead verification workflow.

Use cases

  • Channel routing: send to Telegram only for contacts confirmed to be there.
  • Community and lead research: enrich Telegram handles with bio and avatar data.
  • Verification flows: confirm that a contact has a reachable Telegram account.
  • List cleaning: drop non-Telegram contacts from Telegram-specific campaigns.
  • ID resolution: turn a username or phone number into its numeric Telegram user ID.

Best practices

  • Accept numbers and usernames. Do not force a phone number when a handle is all you have.
  • Validate before enriching. Skip the bio and photo calls for peers that fail the check.
  • Cache userHash for under 24 hours. Reuse the stored hash for repeat profile lookups instead of calling check-exists again.
  • Use reason to debug. It separates a bad number from a bad handle, so you can fix the input instead of retrying blindly.
  • Respect the platform and privacy law. Only process contacts you have a legitimate basis to use.

FAQ

How do I check if a phone number is on Telegram? Call check-exists with the number as +phone in international format, with the plus encoded as %2B in a raw URL. The result tells you whether it exists and, if so, returns the user id, username, display name and a userHash.

Can I look up a Telegram username instead of a number? Yes. The peer can be @username, a bare username, or user:<id> for a numeric ID. A username that does not exist returns exists=false with a reason such as USERNAME_NOT_OCCUPIED.

What is the userHash for and how long does it last? It authorizes the get-about and get-picture lookups for one peer and is valid for 24 hours. A missing or expired hash is rejected, so run check-exists again to get a new one.

Why is the bio empty? An empty about means the user has not set a bio or has hidden it. It is a normal answer rather than a failure, and the API never fabricates text.

How do I save the Telegram profile photo? get-picture returns the image base64-encoded in data with its MIME type, because Telegram photos have no public URL. Decode the string and write the bytes to a file. If pictureSet is false, there is no visible photo.

Try it

Test the checker on the Telegram Number Validation page, or read the check-exists, get-about and get-picture references. See pricing when you are ready to go beyond the free credits.