How to Get a WhatsApp Profile Photo, About Text & Last Seen via API

Published August 23, 2026 Β· UpdatedOctober 9, 2026

A registered WhatsApp number often has a public footprint: a profile photo, an "About" line, and presence signals such as online or last seen. For lead enrichment, identity checks and research, that public profile is valuable, and you can fetch it programmatically.

This guide shows how to pull a number's avatar, About text, presence and business profile, what each result means, and, just as important, what comes back empty and why.

The two-step flow

Profile lookups are gated behind a registration check. That keeps things cheap: you confirm that the number exists first, then spend enrichment credits only on real accounts.

  1. Check registration with check-exist-by-phone. For a registered number (isExist=true) it returns a userHash, valid for 24 hours, and hasExtra, a summary of the enrichment fields available.
  2. Fetch profile data by passing that userHash to the profile operations. The number is resolved on the server, so these operations take no phone parameter, and a missing, unknown or expired hash is rejected.
curl "https://api.opendata-api.com/api/project/whatsapp/check-exist-by-phone?key=YOUR_API_KEY&phoneNumber=15551234567"

Copy the userHash from the response. If you need the full background on the check itself, read the WhatsApp number lookup guide.

Step 2: Fetch the profile fields

Profile photo (avatar):

curl "https://api.opendata-api.com/api/project/whatsapp/get-avatar?key=YOUR_API_KEY&userHash=USER_HASH"

When pictureSet=true, the response includes a temporary photo URL and a picture version id that changes whenever the person changes their photo. If the number is registered but has no photo, or hides it through privacy, you get pictureSet=false and a reason.

About / status text:

curl "https://api.opendata-api.com/api/project/whatsapp/get-about?key=YOUR_API_KEY&userHash=USER_HASH"

This returns the About text and the profile-picture version id. An empty about means the person has no status text or hides it.

Business profile:

curl "https://api.opendata-api.com/api/project/whatsapp/get-biz-profile?key=YOUR_API_KEY&userHash=USER_HASH"

For WhatsApp Business accounts you get the business name, verified level, description, address, email, website and member-since info. A personal number returns isBusiness=false.

Presence / last seen:

curl "https://api.opendata-api.com/api/project/whatsapp/get-presence?key=YOUR_API_KEY&userHash=USER_HASH"

Presence is strongly constrained by the target's privacy. If you are not a contact and the person's last-seen or online setting is not "everyone", presence is not delivered and the result is visible=false. That is a real answer and it cannot be bypassed. A single call can take up to about 17 seconds, so give it a generous timeout and call it only when the signal is worth the wait.

Optional extras

When the check reports additional fields in hasExtra, three more operations exist: get-device-name (the owner's display name, typically only for currently active accounts), get-email (a masked backup email, not a business contact address) and get-wa-old-device-name (the previous device name). Call each one only if hasExtra lists it. When a field is absent, the value is null and message explains why.

A Python example

import requests

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


def get(operation, timeout=30, **params):
    params["key"] = API_KEY
    resp = requests.get(f"{BASE}/{operation}", params=params, timeout=timeout)
    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 enrich(number, with_presence=False):
    found = get("check-exist-by-phone", phoneNumber=number)
    if found.get("isExist") is not True:
        return {"number": number, "registered": found.get("isExist")}

    user_hash = found.get("userHash")
    if not user_hash:
        raise RuntimeError(f"no userHash in reply: {found}")
    avatar = get("get-avatar", userHash=user_hash)
    about = get("get-about", userHash=user_hash)
    profile = {
        "number": number,
        "registered": True,
        "photo_set": bool(avatar.get("pictureSet")),
        "photo_reason": avatar.get("reason"),
        "about": about.get("about") or None,
    }
    if avatar.get("pictureSet") and avatar.get("url"):
        profile["photo_bytes"] = requests.get(avatar["url"], timeout=30).content
    if with_presence:
        presence = get("get-presence", timeout=60, userHash=user_hash)
        profile["presence_visible"] = presence.get("visible")
    return profile


print(enrich("15551234567"))

The photo URL is temporary, so the code downloads the image straight away. Save the bytes yourself if you will need them later.

Detect profile changes

get-about returns the picture version id as pictureId, and it changes when the photo changes (get-avatar reports a picture version id too). Store it with the contact. On the next enrichment, a different value means the person updated their photo, so download the image again; an identical value means you can skip the download. That makes the version id a cheap way to run periodic refreshes without re-fetching every image.

Use cases

  • Lead enrichment: add a face and context to inbound leads before sales outreach.
  • Identity signals: a real photo and About text help distinguish genuine accounts from throwaways, though neither proves who someone is.
  • Activity hints: when presence is visible, it hints at how active a contact is. Plenty of people hide it, so never require it.
  • Business discovery: use the business profile for company details on WhatsApp Business numbers.

Best practices

  • Always check first. Do not call profile operations for numbers that failed registration.
  • Cache userHash for up to 24 hours so repeat enrichments do not repeat the check.
  • Handle empty fields gracefully. Hidden by privacy is normal, not an error: pictureSet=false, an empty about and visible=false are all valid answers.
  • Download photos immediately. The photo URL is temporary.
  • Treat profile data as personal data. Process only numbers you have a lawful basis to use, apply data-minimization, and respect WhatsApp's terms.

How this compares with Telegram

Telegram's profile lookups return the bio and a base64-encoded photo, and they can start from a username instead of a number. If you need both platforms side by side, read WhatsApp vs Telegram number lookup and the Telegram number checker. To combine profile signals with other checks in one scoring flow, see the lead verification workflow.

FAQ

Can I always get a WhatsApp profile photo from a phone number? No. The number must be registered, and the person must not hide their photo through privacy settings. Otherwise the result is pictureSet=false with a reason, which is a normal answer.

Why does get-presence return visible=false? Presence only reaches you if you are a contact or the person allows everyone to see their last seen or online status. When it is hidden, the API honestly reports visible=false; it cannot be bypassed.

How do I know whether a profile photo changed? get-about returns a pictureId that changes when the photo changes (get-avatar reports a picture version id too). Store it and compare on the next lookup.

Why is the get-presence call slow? A single call can take up to about 17 seconds, so use a long timeout and call it only for contacts where the signal matters.

Is the userHash reusable? Yes, for 24 hours. Reuse it across the avatar, About, business and presence calls for the same number, then run the registration check again for a fresh one.

Try it

Fetch a profile live on the WhatsApp Number Validation page, or read the get-avatar, get-about, get-biz-profile and get-presence references. See pricing for per-request costs.