Examples on this page target source snapshot
35a69a14, not a crates.io release. Use the current API guide to select the matching dependency.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.jids- Array of JIDs to check. SupportsJid::pn("phone_number")for phone number lookups andJid::lid("lid_value")for LID lookups. If you pass a non-PN/non-LID JID (groups, newsletters, etc.), the method returns an error immediately.
Vec<IsOnWhatsAppResult>- Registration status for each JID
jid: Jid- WhatsApp JID for the useris_registered: bool- Whether the JID is on WhatsApplid: Option<Jid>- LID (Linked Identity) if availablepn_jid: Option<Jid>- Phone number JID, present when the server returns LID as the primary JIDis_business: bool- Whether this is a WhatsApp Business accountverified_name: Option<VerifiedName>- Decoded verified business name certificate, when the account is a verified businessusername: Option<CompactString>- Meta username, without the display-only@prefix.Nonemeans the server reported no username, which is also how it reports one that was deleted; it is never an empty stringcontact_error: Option<UsyncSubprotocolError>- Server error for thecontactsubprotocol (e.g. privacy-blocked lookup);is_registeredwill befalselid_error: Option<UsyncSubprotocolError>- Server error for thelidsubprotocol;lidwill beNonebusiness_error: Option<UsyncSubprotocolError>- Server error for thebusinesssubprotocol;is_businesswill befalseusername_error: Option<UsyncSubprotocolError>- Server error for theusernamesubprotocol. Unlike the other*_errorfields, this does not implyusernameisNone. The server also publishes a username as a plain attribute of thecontactresult, and a failed subprotocol does not retract that value. Sousernamecan still beSomenext tousername_error.
name: Option<String>- Display name shown to other users (decoded from the certificate when the server omits the attribute)serial: Option<String>- Certificate serial numberissuer: Option<String>- Certificate issuercertificate: Option<Vec<u8>>- RawVerifiedNameCertificateprotobuf 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.Both
is_on_whatsapp and get_user_info now ask for the username subprotocol by default, matching WhatsApp Web’s own existence check and background contact sync. This is not opt-in and adds one more child to the <query> node of both requests.Profile pictures
Use the pictures facade for single contact, group or community lookups. Choose an explicit route and size and preserve unchanged, missing, unauthorized and error outcomes.get_user_info
Get user information by JID.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.HashMap<Jid, UserInfo>- Map of JID to user info
jid: Jid- WhatsApp JIDlid: Option<Jid>- LID if availablelid_error: Option<UsyncSubprotocolError>- Server error for thelidsubprotocol;lidwill beNonestatus: Option<String>- Status messagestatus_error: Option<UsyncSubprotocolError>- Server error for thestatussubprotocol (e.g. privacy-hidden status);statuswill beNonepicture_id: Option<String>- Profile picture IDpicture_error: Option<UsyncSubprotocolError>- Server error for thepicturesubprotocol;picture_idwill beNoneis_business: bool- Whether business accountbusiness_error: Option<UsyncSubprotocolError>- Server error for thebusinesssubprotocol;is_businesswill befalseverified_name: Option<VerifiedName>- Decoded verified business name certificate, for verified business accounts (seeis_on_whatsappfor field details)devices: Vec<u16>- Device IDs from the<devices version="2">sublist the same usync query returns (device0is the primary). Empty when the server omits the sublist — no extra request is needed.devices_error: Option<UsyncSubprotocolError>- Server error for thedevicessubprotocol;deviceswill be emptyusername: Option<CompactString>- Meta username, without the display-only@prefix. SeeIsOnWhatsAppResult::usernamefor how it’s sourced and whatNonemeansusername_error: Option<UsyncSubprotocolError>- Server error for theusernamesubprotocol. SeeIsOnWhatsAppResult::username_error— a value already read from thecontactresult’s attribute survives next to this error
UserInfo is #[non_exhaustive], so new fields may be added in future versions without a breaking change.code: Option<u16>- Numeric error code from the server (e.g.403,404)text: Option<String>- Human-readable error descriptionbackoff: Option<u32>- Server-suggested retry delay in seconds
*_error fields when a corresponding Option field is None and you need to distinguish “not set” from “server error”.
find_by_username
Resolve a Meta username to the account behind it.username- The handle to resolve. A leading@is display-only and is stripped automatically. The bare handle must be betweenUSERNAME_MIN_LENGTH(3) andUSERNAME_MAX_LENGTH(35) characters, or the call fails withContactError::Usernamebefore any request is sent.username_key- The account’s numeric “username key” (WhatsApp Web calls it a pin). Some accounts require it before the server will disclose the identity behind their handle at all.
UsernameLookup:
NotFound- No account answers to this username, or it’s not reachable from hereKeyRequired { username: Option<CompactString> }- The username exists but the server withheld the identity; repeat the call with the account’s username keyFound(UsernameLookupUser)- The username resolved to an account
jid: Jid- Identity the server returned. The query addresses contacts by LID, so this is normally a LIDpn_jid: Option<Jid>- Phone-number JID, when the server disclosed one on<business>username: Option<CompactString>- Username as the server spelled it backis_business: boolverified_name: Option<VerifiedName>
Found, the discovered LID/PN pair is persisted to the local cache, the same way is_on_whatsapp and get_user_info do.
Example:
Types
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 returnResult<T, ContactError>:
Username is returned by find_by_username when the handle can’t be turned into a valid lookup — too short, too long, or a username_key that fails usync’s own field-consistency validation.
Batch operations
All lookup methods support batch operations for efficiency:Contact notification events
The server sendscontacts 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
These are server-push notifications, distinct from
ContactUpdate and ContactRemoved, which come from app-state sync mutations made on a linked device. See Chat actions — Save and remove contacts for save_contact/remove_contact and their events.Empty input handling
Passing empty arrays returns empty results without making network requests:Migration from previous versions
Theis_on_whatsapp method previously accepted &[&str] (phone number strings). It now takes &[Jid]:
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).
Learning LID and phone aliases
On main snapshot35a69a14, contact lookups learn PN-primary results with LID fields and LID-primary results with explicit PN fields, including business usync responses. The client validates the identity families and user identifiers before storing a pair. Mapping persistence errors are logged; a successful contact lookup does not itself prove that an alias reached durable storage.
App-state contact actions also persist validated LID/PN pairs before advancing their collection cursor or publishing observations. A mapping write failure leaves that update retryable. Multiple retained mappings keep deterministic application order and the existing last-LID-per-phone policy.
A learned alias helps routing and lookup. It does not authorize rewriting a stored cryptographic creator or merging unrelated message IDs. Preserve the original creator for polls, events and encrypted message actions, and keep consumer deduplication scoped by chat, sender and ID.
Startup PN/LID warm-up preserves newer live mappings learned while backend reads are in flight. Treat cached aliases as validated observations with provenance, not authority to rewrite original cryptographic creators or message IDs. A completed lookup still does not prove durable persistence of a learned pair.