Skip to main content
The Contacts struct provides methods for checking WhatsApp registration status and retrieving profile pictures and user information.

Access

Access contact operations through the client:

Methods

is_on_whatsapp

Check if JIDs are registered on WhatsApp. Accepts both PN JIDs and LID JIDs.
Parameters:
  • jids - Array of JIDs to check. Supports Jid::pn("phone_number") for phone number lookups and Jid::lid("lid_value") for LID lookups. If you pass a non-PN/non-LID JID (groups, newsletters, etc.), the method returns an error immediately.
Returns:
  • Vec<IsOnWhatsAppResult> - Registration status for each JID
IsOnWhatsAppResult fields:
  • jid: Jid - WhatsApp JID for the user
  • is_registered: bool - Whether the JID is on WhatsApp
  • lid: Option<Jid> - LID (Linked Identity) if available
  • pn_jid: Option<Jid> - Phone number JID, present when the server returns LID as the primary JID
  • is_business: bool - Whether this is a WhatsApp Business account
  • verified_name: Option<VerifiedName> - Decoded verified business name certificate, when the account is a verified business
  • contact_error: Option<UsyncSubprotocolError> - Server error for the contact subprotocol (e.g. privacy-blocked lookup); is_registered will be false
  • lid_error: Option<UsyncSubprotocolError> - Server error for the lid subprotocol; lid will be None
  • business_error: Option<UsyncSubprotocolError> - Server error for the business subprotocol; is_business will be false
VerifiedName fields:
  • name: Option<String> - Display name shown to other users (decoded from the certificate when the server omits the attribute)
  • serial: Option<String> - Certificate serial number
  • issuer: Option<String> - Certificate issuer
  • certificate: Option<Vec<u8>> - Raw VerifiedNameCertificate protobuf bytes, for callers that need to verify the signature themselves
IsOnWhatsAppResult is marked #[non_exhaustive], so new fields may be added in future versions without a breaking change.
Example — phone number lookup:
Example — LID lookup:
PN and LID queries use different wire protocols (matching WhatsApp Web’s ExistsJob), so mixed inputs are automatically split into separate requests. LID-PN mappings discovered from results are persisted to the local cache.

get_profile_picture

Get the profile picture URL for a JID.
Parameters:
  • jid - Target JID (user, group, or newsletter)
  • preview - true for preview thumbnail, false for full-size image
Returns:
  • Option<ProfilePicture> - Picture info or None if not available
ProfilePicture fields:
  • id: String - Picture ID
  • url: String - Download URL
  • direct_path: Option<String> - Direct path for media download
  • hash: Option<String> - SHA-256 hash for integrity and cache validation
Example:
For groups:
To override the default request timeout for a single fetch, use get_profile_picture_with_timeout(jid, preview, timeout), which takes an extra timeout: Option<Duration> argument. Internally the request is built via ProfilePictureSpec’s with_timeout(...) builder method; pass None to fall back to the default timeout.
The system/announcements JID (0@s.whatsapp.net, and its legacy form 0@c.us) never answers this IQ, so it’s short-circuited client-side: both get_profile_picture and get_profile_picture_with_timeout return Ok(None) immediately for it instead of waiting out the full request timeout. This mirrors WhatsApp Web, which never sends the request for this JID in the first place.

get_user_info

Get user information by JID.
Parameters:
  • jids - Array of JIDs to query
The system/announcements JID (0@s.whatsapp.net, and its legacy form 0@c.us) is filtered out of the batch before it’s sent — it’s not usync-eligible and the server never answers for it. If it’s the only JID passed in, get_user_info returns an empty map without making a request; if it’s mixed with other JIDs, the remaining JIDs are still queried normally.
Returns:
  • HashMap<Jid, UserInfo> - Map of JID to user info
UserInfo fields:
  • jid: Jid - WhatsApp JID
  • lid: Option<Jid> - LID if available
  • lid_error: Option<UsyncSubprotocolError> - Server error for the lid subprotocol; lid will be None
  • status: Option<String> - Status message
  • status_error: Option<UsyncSubprotocolError> - Server error for the status subprotocol (e.g. privacy-hidden status); status will be None
  • picture_id: Option<String> - Profile picture ID
  • picture_error: Option<UsyncSubprotocolError> - Server error for the picture subprotocol; picture_id will be None
  • is_business: bool - Whether business account
  • business_error: Option<UsyncSubprotocolError> - Server error for the business subprotocol; is_business will be false
  • verified_name: Option<VerifiedName> - Decoded verified business name certificate, for verified business accounts (see is_on_whatsapp for field details)
  • devices: Vec<u16> - Device IDs from the <devices version="2"> sublist the same usync query returns (device 0 is the primary). Empty when the server omits the sublist — no extra request is needed.
  • devices_error: Option<UsyncSubprotocolError> - Server error for the devices subprotocol; devices will be empty
UserInfo is #[non_exhaustive], so new fields may be added in future versions without a breaking change.
UsyncSubprotocolError fields:
  • code: Option<u16> - Numeric error code from the server (e.g. 403, 404)
  • text: Option<String> - Human-readable error description
  • backoff: Option<u32> - Server-suggested retry delay in seconds
The library preserves per-subprotocol errors on the result struct rather than failing the whole request. A privacy error from one user’s status does not block retrieval of devices for other users in the same batch. Check the *_error fields when a corresponding Option field is None and you need to distinguish “not set” from “server error”.
Example:

Privacy & TC tokens

For user JIDs (not groups/newsletters), the library automatically includes TC tokens when fetching profile pictures. TC tokens are used for privacy-gated operations. The implementation automatically:
  • Looks up TC tokens for user JIDs
  • Includes tokens in profile picture requests
  • Skips tokens for groups and newsletters
get_user_info does the same for status/about: when the profile_scraping_privacy_token_in_about_usync AB prop is on, each queried JID’s TC token is attached to its <user> node in the usync IQ, matching WhatsApp Web’s USyncStatusProtocol. This is what lets status/status_error and about resolve correctly for a privacy-restricted contact instead of coming back hidden. See TC Token for details.

Async compatibility

is_on_whatsapp and get_user_info work correctly when called from #[async_trait] implementations or any context that boxes the returned future (Box<dyn Future + Send>). Earlier versions produced a compile error ("implementation of FnOnce is not general enough") that could not be worked around in user code. Fixed in #826 with no API changes.

Error handling

All methods return Result<T, ContactError>:

Batch operations

All lookup methods support batch operations for efficiency:

Contact notification events

The server sends contacts notifications when contact data changes. These are emitted as events you can subscribe to:
  • ContactUpdated — a contact’s profile changed (invalidate cached presence/profile picture)
  • ContactNumberChanged — a contact changed their phone number (includes old/new JID and optional LID mappings)
  • ContactSyncRequested — the server requests a full contact re-sync
See the events reference for full struct definitions and wire format details.

Empty input handling

Passing empty arrays returns empty results without making network requests:

Migration from previous versions

The is_on_whatsapp method previously accepted &[&str] (phone number strings). It now takes &[Jid]:
The get_info method and ContactInfo type have been removed. Use is_on_whatsapp for registration checks (now includes lid, pn_jid, and is_business fields) or get_user_info for detailed profile data (status, picture ID).