Groups struct provides methods for managing WhatsApp groups, including creating groups, managing participants, and modifying group settings.
Access
Access group operations through the client:Methods
query_info
Query group information with caching support.jid- Group JID (must end with@g.us)
Arc<GroupInfo>- Shared, reference-counted snapshot containing the participants list and addressing mode. Repeated calls for the same group return the sameArcfrom the in-memory cache, so warm sends avoid deep-cloning group metadata.
query_info_with_freshness
Query group information with an explicit cache Freshness policy, instead of the always-cache-preferred behavior of query_info.
jid- Group JID (must end with@g.us)freshness-Freshness::CachePreferred(same asquery_info) orFreshness::Refreshto force a network round-trip
Arc<GroupInfo>- Same shared snapshot type asquery_info
Refresh query leaves the currently cached snapshot readable to concurrent callers while the network request is in flight, then atomically replaces it once the response arrives — there is no window where the cache is empty.
Example:
get_participating
Get all groups the client is participating in.HashMap<Jid, GroupMetadata>- Map of groupJidto metadata
This map is keyed by
Jid. Call .to_string() on the key if you need the string form.GroupMetadata implements PartialEq and Eq, allowing direct comparison of group metadata instances.
GroupMetadata fields:
id: Jid- Group JIDsubject: String- Group namenotify: Option<String>- Display notification string reported by the server (from thenotifyattribute)participants: Vec<GroupParticipant>- List of participantsaddressing_mode: AddressingMode- Phone number or LID modecreator: Option<Jid>- Group creator JIDcreator_pn: Option<Jid>- Creator’s phone-number JID, whencreatoris a LIDcreator_username: Option<String>- Creator’s Meta username, when presentcreator_country_code: Option<String>- Creator’s ISO country code, when presentcreation_time: Option<u64>- Group creation timestamp (Unix seconds)participant_version_id: Option<String>- Participant-list version identifier (fromp_v_id)admin_version_id: Option<String>- Admin-list version identifier (froma_v_id)open_thread_id: Option<String>- Open thread identifier associated with the grouphas_missing_participant_identification: bool- Whether participant identity information was incomplete in this responsesubject_time: Option<u64>- Subject modification timestamp (Unix seconds)subject_owner: Option<Jid>- Subject owner JIDsubject_owner_pn: Option<Jid>- Subject owner’s phone-number JID (froms_o_pn)subject_owner_username: Option<String>- Subject owner’s Meta username (froms_o_username)description: Option<String>- Group description body textdescription_id: Option<String>- Description ID (for conflict detection)description_owner: Option<Jid>- JID of the participant who set the descriptiondescription_owner_pn: Option<Jid>- Description owner’s phone-number JIDdescription_owner_username: Option<String>- Description owner’s Meta usernamedescription_time: Option<u64>- Timestamp when the description was set (Unix seconds)is_locked: bool- Whether only admins can edit group infois_announcement: bool- Whether only admins can send messagesephemeral: Option<GroupEphemeralSettings>- Disappearing-message settings.Nonewhen the server response has no<ephemeral>node at all;Some(GroupEphemeralSettings { expiration, trigger })when the node is present —expirationisNoneif the node omitted the attribute, which is distinct fromSome(0)(timer explicitly disabled)membership_approval: bool- Whether admin approval is required to joinmember_add_mode: Option<MemberAddMode>- Who can add membersmember_link_mode: Option<MemberLinkMode>- Who can use invite linkssize: Option<u32>- Total participant countis_parent_group: bool- Whether this group is a community parent groupparent_membership_approval_required: bool- Whether joins to this parent group require approval by defaultparent_group_jid: Option<Jid>- JID of the parent community (for subgroups)is_default_sub_group: bool- Whether this is the default announcement subgroup of a communityis_general_chat: bool- Whether this is the general chat subgroup of a communityallow_non_admin_sub_group_creation: bool- Whether non-admin community members can create subgroupsno_frequently_forwarded: bool- Whether frequently-forwarded messages are restrictedmember_share_history_mode: Option<MemberShareHistoryMode>- Who can share message history with new membersgrowth_locked: Option<GrowthLockInfo>- Growth lock status (invite links temporarily disabled by the system)is_suspended: bool- Whether the group is suspendedsuspension_can_auto_file: bool- Whether a suspension appeal may be filed automaticallyappeal_status: Option<GroupAppealStatus>- Current suspension-appeal stateappeal_update_time: Option<u64>- Last suspension-appeal update timestamp (Unix seconds)is_support_group: bool- Whether the group is marked as a support groupallow_admin_reports: bool- Whether admin reports are allowedis_hidden_group: bool- Whether the group is hiddenis_incognito: bool- Whether incognito mode is enabledhas_group_history: bool- Whether group history is enabledis_auto_add_disabled: bool- Whether automatic participant addition is disabledhas_capi: bool- Whether the group carries the CAPI capability markerevolution_version: Option<u32>- Group schema evolution versionhas_group_safety_check: bool- Whether the group safety-check feature is enabledparticipant_label_enabled: bool- Whether participant labels are enabledis_limit_sharing_enabled: bool- Whether limit sharing is enabledlimit_sharing_trigger: Option<u32>- Source trigger for limit-sharing enablement
ephemeral_expiration: u32 and ephemeral_trigger: Option<u32> were replaced by the single ephemeral: Option<GroupEphemeralSettings> field. Migrate reads like metadata.ephemeral_expiration to metadata.ephemeral.as_ref().and_then(|e| e.expiration).unwrap_or(0).GroupParticipant implements PartialEq and Eq.
GroupParticipant fields:
jid: Jid- Participant JIDphone_number: Option<Jid>- Phone number JID (for LID groups)lid: Option<Jid>- Participant’s LID JID, when the server includes oneusername: Option<CompactString>- Participant’s Meta username, when presentparticipant_type: ParticipantType- Participant role (member, admin, or super admin)details: Option<Box<GroupParticipantDetails>>- Less-common participant metadata (label, join time, display name, etc.); boxed and only populated when at least one field is present
get_metadata
Get metadata for a specific group.jid- Group JID
GroupMetadata- Owned, full user-facing metadata: subject, description, creator, per-participant admin roles, and ephemeral/membership settings (seeget_participatingfor the full field list). In a LID-addressed group, participant phone numbers the server left out are backfilled from known LID/PN mappings on a best-effort basis; a participant with no known mapping keepsphone_number: None.
not-modified) and the result does not populate the group cache. Use this for displaying or auditing a group; when you only need the participant list to send a message, prefer the cached query_info.
Example:
create_group
Create a new group.options: GroupCreateOptions- Group creation optionssubject: String- Group name (max 100 characters)participants: Vec<GroupParticipantOptions>- Initial participantsmember_link_mode: Option<MemberLinkMode>- Who can use invite links (default:AdminLink)member_add_mode: Option<MemberAddMode>- Who can add members (default:AllMemberAdd)membership_approval_mode: Option<MembershipApprovalMode>- Require admin approval (default:Off)ephemeral_expiration: Option<u32>- Disappearing messages timer in seconds (default:0)is_parent: bool- Create as a community parent group (default:false)closed: bool- Whether the community requires approval to join. Only used whenis_parentistrue(default:false)allow_non_admin_sub_group_creation: bool- Allow non-admin members to create subgroups. Only used whenis_parentistrue(default:false)create_general_chat: bool- Create a general chat subgroup alongside the community. Only used whenis_parentistrue(default:false)linked_parent: Option<Jid>- Atomically link this group as a subgroup of an existing community on create. Mutually exclusive withis_parent— when set, the new group is always classified as a subgroup even ifis_parent: trueis also passed. (added in v0.6)description: Option<String>- Inline group description, emitted as a<description>child of the<create>stanza so it lands in one round-trip. Matches the existing community-create behavior. (added in v0.6)
CreateGroupResultwith ametadata: GroupMetadatafield carrying the full server response (JID, subject, addressing mode, participants with display names, parent/community linkage, etc.).
PRIVACY_TOKEN_ON_GROUP_CREATE AB prop is enabled, the library automatically resolves and attaches privacy tokens (tc_token) to each participant during group creation. This is handled internally — you don’t need to manage tokens yourself.
Example:
Since v0.6,
create_group returns the full GroupMetadata (matching get_metadata) instead of just the JID. Inspect result.metadata for participants, addressing mode, ephemeral timer, and parent linkage in a single round-trip. GroupMetadata.participants is a Vec<GroupParticipant> (the IQ-response shape), not the GroupParticipantInfo used by group notification events — but masked-number display_name labels are available here too, via participant.details.as_ref().and_then(|d| d.display_name.as_deref()), in addition to the event-side GroupParticipantInfo.display_name for live group-update events.set_subject
Change the group name.jid- Group JIDsubject- New group name (max 100 characters)
set_description
Set or delete the group description.jid- Group JIDdescription- New description (max 2048 characters) orNoneto deleteprev- The description this update replaces, as aPreviousDescription. The server accepts the update only when this token matches the group’s current description id — a group that already has a description cannot be updated without it.
PreviousDescription::Resolve (the default) reads the current id from the server first, which always works but costs one extra query. If you already hold fresh GroupMetadata::description_id, pass it directly — metadata.description_id.as_deref().into() — to skip that query. Use PreviousDescription::Absent for a group you know has no description yet, such as one you just created.GroupError::DescriptionConflict if the group’s description changed on the server between the read and this update (for example, another device changed it first).
Example:
leave
Leave a group.jid- Group JID to leave
add_participants
Add participants to a group.jid- Group JIDparticipants- Array of participant JIDs to add
Vec<ParticipantChangeResponse>- Result for each participant
PRIVACY_TOKEN_ON_GROUP_PARTICIPANT_ADD AB prop is enabled, the library automatically resolves and attaches privacy tokens (tc_token) to each participant. This is handled internally — you don’t need to manage tokens yourself.
Example:
remove_participants
Remove participants from a group.jid- Group JIDparticipants- Array of participant JIDs to remove
Vec<ParticipantChangeResponse>- Result for each participant
remove_participants_including_linked_groups
Remove participants from a group and cascade the removal to its linked/child groups. Used for community-linked groups, where removing someone from the community should also remove them from subgroups.jid- Group JID (typically the community parent group)participants- Array of participant JIDs to remove
Vec<ParticipantChangeResponse>- Result for each participant
promote_participants
Promote participants to admin.jid- Group JIDparticipants- Array of participant JIDs to promote
Vec<ParticipantChangeResponse>- Result for each participant
promote_participants returns Vec<ParticipantChangeResponse> (one entry per participant) instead of ().demote_participants
Demote admin participants to regular members.jid- Group JIDparticipants- Array of admin JIDs to demote
Vec<ParticipantChangeResponse>- Result for each participant
demote_participants returns Vec<ParticipantChangeResponse> (one entry per participant) instead of ().get_invite_link
Get or reset the group invite link.jid- Group JIDreset- Whether to reset and generate a new invite link
String- Invite link code
join_with_invite_code
Join a group using an invite code or full invite URL.code- Invite code or full URL (e.g.,"AbCdEfGh"or"https://chat.whatsapp.com/AbCdEfGh")
JoinGroupResult- EitherJoined(Jid)if immediately joined, orPendingApproval(Jid)if the group requires admin approval
join_with_invite_v4
Accept a V4 group invite received as aGroupInviteMessage (not a link). V4 invites are sent directly by a group admin as a message, rather than shared as a URL.
group_jid- The target group JIDcode- Invite code from theGroupInviteMessageexpiration- Invite expiration timestamp (Unix seconds). The method returns an error if the invite has expired.admin_jid- JID of the admin who sent the invite
JoinGroupResult- EitherJoined(Jid)if immediately joined, orPendingApproval(Jid)if the group requires admin approval
V4 invites expire. The method automatically checks the expiration timestamp and returns an error if the invite has already expired. You can pass
0 as the expiration to skip the expiration check.get_invite_info
Get group metadata from an invite code without joining the group.code- Invite code or full URL
GroupMetadata- Group metadata (seeget_participatingfor fields)
set_locked
Lock or unlock the group so only admins can change group info.jid- Group JIDlocked-trueto lock (only admins edit info),falseto unlock
set_announce
Set announcement mode. When enabled, only admins can send messages.jid- Group JIDannounce-trueto enable (only admins send),falseto disable
set_ephemeral
Set the disappearing messages timer on the group.jid- Group JIDexpiration- Timer duration in seconds. Common values:86400(24 hours),604800(7 days),7776000(90 days). Pass0to disable.
set_membership_approval
Set membership approval mode. When enabled, new members must be approved by an admin.jid- Group JIDmode-MembershipApprovalMode::Onto require approval,MembershipApprovalMode::Offto disable
get_membership_requests
Get pending membership approval requests for a group.jid- Group JID
Vec<MembershipRequest>- List of pending requests
approve_membership_requests
Approve pending membership requests for a group.jid- Group JIDparticipants- Array of JIDs to approve
Vec<ParticipantChangeResponse>- Result for each participant
reject_membership_requests
Reject pending membership requests for a group.jid- Group JIDparticipants- Array of JIDs to reject
Vec<ParticipantChangeResponse>- Result for each participant
set_member_add_mode
Set who can add members to the group.jid- Group JIDmode-MemberAddMode::AdminAddto restrict to admins,MemberAddMode::AllMemberAddto allow all members
set_no_frequently_forwarded
Restrict or allow frequently-forwarded messages in the group.jid- Group JIDrestrict-trueto restrict frequently-forwarded messages,falseto allow them
set_allow_admin_reports
Enable or disable admin reports in the group.jid- Group JIDallow-trueto enable admin reports,falseto disable
set_group_history
Enable or disable group history sharing.jid- Group JIDenabled-trueto enable group history,falseto disable
set_member_link_mode
Set who can share invite links. This uses the MEX (Mutation Exchange) protocol.jid- Group JIDmode-MemberLinkMode::AdminLinkto restrict to admins,MemberLinkMode::AllMemberLinkto allow all members
set_member_share_history_mode
Set who can share message history with new members. This uses the MEX protocol.jid- Group JIDmode-MemberShareHistoryMode::AdminShareto restrict to admins,MemberShareHistoryMode::AllMemberShareto allow all members
set_limit_sharing
Enable or disable limit sharing in the group. This uses the MEX protocol.jid- Group JIDenabled-trueto enable limit sharing,falseto disable
cancel_membership_requests
Cancel pending membership requests from the requesting user’s side.jid- Group JIDparticipants- Array of JIDs whose pending requests to cancel
Vec<ParticipantChangeResponse>- Result for each participant
revoke_request_code
Revoke invitation codes from specific participants. This is an admin operation.jid- Group JIDparticipants- Array of participant JIDs whose invitation codes to revoke
Vec<ParticipantChangeResponse>- Result for each participant
acknowledge
Acknowledge a group notification.jid- Group JID
update_member_label_with_id
Set or clear the bot’s per-group member label, sent as aProtocolMessage over the normal message path (not an IQ). Returns the sent stanza’s message ID.
group_jid- Group JIDlabel- New label text, or an empty string to clear the label
String- Message ID of the sent stanza
update_member_label is a thin wrapper around update_member_label_with_id that discards the message ID and returns Result<(), GroupError>, for callers that don’t need it.batch_get_info
Batch query group info for multiple groups at once.jids- List of group JIDs to query (max 10,000)
Vec<BatchGroupResult>- Result for each group
set_profile_picture
Set a group’s profile picture. Admin operation.group_jid- Group JID (must end with@g.us)image_data- JPEG image bytes. The caller is responsible for sizing/cropping the image (WhatsApp uses 640x640).
SetProfilePictureResponse- Contains the new picture ID
image_data routes to removal, mirroring the own-picture API. Prefer remove_profile_picture when removal is the intent.
Example:
remove_profile_picture
Remove a group’s profile picture. Admin operation.group_jid- Group JID
SetProfilePictureResponse- Confirmation of removal
SetProfilePictureResponse for the response shape.
get_profile_pictures
Batch fetch group profile pictures.group_jids- List of group JIDs (max 1,000)picture_type-PictureType::Previewfor thumbnails orPictureType::Imagefor full-size
Vec<GroupProfilePicture>- Profile picture data for each group
Types
Freshness
Selects whether an operation may return an existing cached snapshot or must consult its source before returning. Shared across the SDK wherever a cache-backed lookup accepts an explicit staleness policy — Groups::query_info_with_freshness here, and StatusSendOptions::device_freshness (see Status).
Freshness is re-exported from the crate root, so you can import it directly: use whatsapp_rust::Freshness;. When you pass Refresh, you never see a caller-visible gap — the previous snapshot stays servable until the new one is published.
GroupInfo
Cached group information returned byquery_info. Contains participant list, addressing mode, and LID-to-phone mappings for privacy-addressed groups.
query_info returns Arc<GroupInfo> so that repeated lookups and warm sends share the same snapshot without deep-cloning the participants list.
Example:
GroupSubject
Validated group name with 100 character limit.GroupDescription
Validated group description with 2048 character limit.PreviousDescription
The description aset_description call expects to replace — the server’s optimistic-concurrency token for the group’s description.
Resolve(default) — read the group’s current description id from the server before sending. The only variant that’s correct without knowing anything about the group, and the only one that costs a round trip.Absent— the group carries no description yet (e.g. one you just created), so no token is sent.Id(&str)— a description id you already hold, typicallyGroupMetadata::description_idfrom a recentget_metadatacall.
From<Option<&str>> lets you turn a held GroupMetadata::description_id into a token directly: None maps to Absent (that metadata says the group has no description), Some(id) maps to Id(id). Use Resolve instead when the metadata’s age is unknown, since stale metadata that missed a description added since would otherwise surface as GroupError::DescriptionConflict.
GroupEphemeralSettings
Disappearing-message settings carried by a group’s<ephemeral> node.
MemberAddMode
ParticipantType
Participant role within a group.is_admin(&self) -> bool- Returnstrueif admin or super admin
GroupParticipantDetails
Less-common participant metadata. Boxed onGroupParticipant/GroupParticipantResponse and only populated when at least one field is present.
GroupParticipantDetails is #[non_exhaustive]. Field reads are unaffected; only exhaustive struct destructuring from outside the crate requires adding ...MemberLinkMode
Controls who can use invite links to join the group.MemberShareHistoryMode
Controls who can share message history with new members.MembershipApprovalMode
GroupAppealStatus
Review state for an appeal on a suspended group.GroupParticipantOptions
Options for specifying a participant when creating or modifying a group.GroupParticipantOptions::new(jid)- Create from a JIDGroupParticipantOptions::from_phone(phone_number)- Create from a phone number JIDGroupParticipantOptions::from_lid_and_phone(lid, phone_number)- Create from a LID and phone number
.with_phone_number(jid)- Attach a phone number JID (for LID participants).with_privacy(token)- Attach a privacy token (tc_tokenbytes)
You typically don’t need to set the
privacy field manually. When AB props are enabled, the library automatically resolves and attaches privacy tokens during create_group and add_participants operations.JoinGroupResult
Result of joining a group via invite code.group_jid(&self) -> &Jid- Returns the group JID regardless of result variant
MembershipRequest
A pending membership approval request.ParticipantChangeResponse
Result of a participant change operation (add, remove, approve, reject).ParticipantChangeResponse is #[non_exhaustive]. Field reads are unaffected; only exhaustive struct destructuring from outside the crate requires adding ...add_request is populated when the server responds with HTTP 403 carrying an <add_request> child — that happens when a participant has privacy blocked direct adds and the inviter must send them a v4 invite link out-of-band. Since v0.6 the value is preserved instead of being dropped, so consumers can drive the v4 invite flow without parsing the raw IQ.
AddressingMode
BatchGroupResult
Result for a single group in a batch query.GrowthLockInfo
Growth lock information (system-managed, read-only). When present, invite links are temporarily disabled by the system.PictureType
Profile picture query type for batch fetching.GroupProfilePicture
A single group profile picture result from a batch query.CreateGroupResult
Result of creating a group.CreateGroupResult is #[non_exhaustive]. Field reads are unaffected; only exhaustive struct destructuring from outside the crate requires adding ...metadata field carries the full group state returned by the server (same shape as get_metadata). metadata.participants is Vec<GroupParticipant> — masked-number display_name labels are reachable via participant.details.as_ref().and_then(|d| d.display_name.as_deref()), or from the event-side GroupParticipantInfo (which carries <participant> children of notification events) when handling live group-update events.
Prior to v0.6 this struct only exposed a
gid: Jid. Replace result.gid with result.metadata.id when upgrading (GroupMetadata.id, not jid). The same migration applies to CreateCommunityResult.GroupJoinError
Error codes returned when joining a group via invite fails.from_code(code: u16) -> Self- Create from a numeric status codecode(&self) -> u16- Get the numeric status code
InviteInfoError
Error codes returned when fetching group info from an invite code.from_code(code: u16) -> Self- Create from a numeric status codecode(&self) -> u16- Get the numeric status code
Error types
GroupError
All group methods return Result<T, GroupError>:
Iq— IQ request failed (timeout, server rejection, etc.)Mex— MEX protocol error (for methods using the MEX transport)InvalidRequest— malformed request (expired invite, missing fields, etc.)DescriptionConflict—set_description’sprevtoken no longer matches the group’s current description (the server answered409 conflict); another device changed it first. Kept distinct from a permission refusal so a caller can re-read the description and retry instead of giving up.Internal— catch-all for other errors