> ## Documentation Index
> Fetch the complete documentation index at: https://whatsapp-rust.jlucaso.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Group Management

> Learn how to create groups, manage participants, and update group metadata in whatsapp-rust

## Overview

This guide covers group operations including creation, participant management, and metadata updates using the whatsapp-rust library.

## Accessing the groups API

All group operations are accessed through the `groups()` method:

```rust theme={null}
use whatsapp_rust::client::Client;

let groups = client.groups();
```

See [Groups API reference](/api/groups) for the full API.

## Creating groups

### Basic group creation

```rust theme={null}
use whatsapp_rust::features::groups::{GroupCreateOptions, GroupParticipantOptions};
use wacore_binary::jid::Jid;

let participant1: Jid = "1234567890@s.whatsapp.net".parse()?;
let participant2: Jid = "9876543210@s.whatsapp.net".parse()?;

let options = GroupCreateOptions {
    subject: "My New Group".to_string(),
    participants: vec![
        GroupParticipantOptions::new(participant1),
        GroupParticipantOptions::new(participant2),
    ],
    ..Default::default()
};

let result = client.groups().create_group(options).await?;
println!("Group created with JID: {}", result.gid);
```

See [Groups API reference](/api/groups#create_group) for full details.

### Group creation options

```rust theme={null}
use whatsapp_rust::features::groups::{
    MemberAddMode,
    MemberLinkMode,
    MembershipApprovalMode,
};

let options = GroupCreateOptions {
    subject: "Advanced Group".to_string(),
    participants: vec![
        GroupParticipantOptions::new(participant1),
    ],
    // Control who can add members
    member_add_mode: Some(MemberAddMode::AdminAdd),

    // Control membership approval requirement
    membership_approval_mode: Some(MembershipApprovalMode::On),

    // Control who can share invite links
    member_link_mode: Some(MemberLinkMode::AdminLink),

    // Create as a community parent group
    is_parent: false,

    // Whether the community requires approval to join (only used with is_parent)
    closed: false,

    // Allow non-admin members to create subgroups (only used with is_parent)
    allow_non_admin_sub_group_creation: false,

    // Create a general chat subgroup (only used with is_parent)
    create_general_chat: false,

    ..Default::default()
};

let result = client.groups().create_group(options).await?;
```

You can also use the builder pattern:

```rust theme={null}
let options = GroupCreateOptions::builder()
    .subject("Advanced Group")
    .member_add_mode(MemberAddMode::AdminAdd)
    .membership_approval_mode(MembershipApprovalMode::On)
    .member_link_mode(MemberLinkMode::AdminLink)
    .build();
```

See [Groups API reference](/api/groups#create_group) for all options.

### Group constraints

```rust theme={null}
use whatsapp_rust::features::groups::*;

// GroupSubject: Max 100 characters (used for set_subject)
let subject = GroupSubject::new("A".repeat(101));
assert!(subject.is_err());  // Fails validation

// GroupDescription: Max 2048 characters (used for set_description)
let description = GroupDescription::new("B".repeat(2049));
assert!(description.is_err());  // Fails validation

// Participants: Max 257 (256 + creator)
// GROUP_SIZE_LIMIT = 257
```

<Note>
  `GroupCreateOptions.subject` is a plain `String`. Validated types `GroupSubject` and `GroupDescription` are used by `set_subject` and `set_description` respectively.
</Note>

## Querying group information

### Get group metadata

```rust theme={null}
let group_jid: Jid = "120363012345678@g.us".parse()?;

let metadata = client.groups().get_metadata(&group_jid).await?;

println!("Group: {}", metadata.subject);
println!("Participants: {}", metadata.participants.len());
println!("Addressing mode: {:?}", metadata.addressing_mode);

for participant in &metadata.participants {
    println!("- {} ({:?}, admin: {})",
        participant.jid,
        participant.participant_type,
        participant.is_admin(),
    );
    if participant.is_super_admin() {
        println!("  ^ Group creator");
    }
    if let Some(phone) = &participant.phone_number {
        println!("  Phone: {}", phone);
    }
}
```

See [Groups API reference](/api/groups#get_metadata) for metadata fields.

### List all groups

```rust theme={null}
use std::collections::HashMap;

let groups: HashMap<String, GroupMetadata> = client
    .groups()
    .get_participating()
    .await?;

for (jid, metadata) in groups {
    println!("{}: {} ({} members)",
        jid,
        metadata.subject,
        metadata.participants.len()
    );
}
```

See [Groups API reference](/api/groups#get_participating) for details.

### Query group info (internal)

For lower-level access with caching:

```rust theme={null}
use std::sync::Arc;
use wacore::client::context::GroupInfo;

// `query_info` returns an `Arc<GroupInfo>` so repeated lookups and warm sends
// share the same snapshot without copying the participants list.
let info: Arc<GroupInfo> = client.groups().query_info(&group_jid).await?;

println!("Participants: {:?}", info.participants);
println!("Addressing mode: {:?}", info.addressing_mode);

// Look up phone numbers for LID participants
for participant in &info.participants {
    if let Some(phone_jid) = info.phone_jid_for_lid_user(&participant.user) {
        println!("LID {} -> Phone {}", participant, phone_jid);
    }
}
```

See [Groups API reference](/api/groups#query_info) for details.

## Updating group metadata

### Change group subject

```rust theme={null}
let new_subject = GroupSubject::new("Updated Group Name")?;

client.groups().set_subject(&group_jid, new_subject).await?;
```

See [Groups API reference](/api/groups#set_subject) for details.

### Set or delete group description

```rust theme={null}
use whatsapp_rust::features::groups::{GroupDescription, PreviousDescription};

// Set description — resolves the current description id from the server automatically
let description = GroupDescription::new("This is the group description")?;
client.groups().set_description(
    &group_jid,
    Some(description),
    PreviousDescription::Resolve,
).await?;

// Delete description
client.groups().set_description(
    &group_jid,
    None,
    PreviousDescription::Resolve,
).await?;
```

See [Groups API reference](/api/groups#set_description) for details.

<Note>
  `prev` is an optimistic-concurrency token, not an optional hint: a group that already has a description can only be updated by naming the id it replaces, or the server answers `409 conflict` (surfaced as [`GroupError::DescriptionConflict`](/api/groups#grouperror)). `PreviousDescription::Resolve` reads that id from the server first — the safe default when you don't already have it. If you just fetched `GroupMetadata`, skip the extra round trip by passing its id directly: `metadata.description_id.as_deref().into()`. Use `PreviousDescription::Absent` for a group you know has no description yet, such as one you just created.
</Note>

## Managing participants

### Add participants

```rust theme={null}
let new_members = vec![
    "1111111111@s.whatsapp.net".parse()?,
    "2222222222@s.whatsapp.net".parse()?,
];

let responses = client.groups().add_participants(
    &group_jid,
    &new_members,
).await?;

// Check results
for response in responses {
    match response.status.as_deref() {
        Some("200") => println!("Added: {}", response.jid),
        Some("403") => println!("Failed to add {} (permission denied)", response.jid),
        Some("409") => println!("{} is already in the group", response.jid),
        other => println!("Error adding {}: {:?}", response.jid, other),
    }
}
```

See [Groups API reference](/api/groups#add_participants) for response codes.

### Remove participants

```rust theme={null}
let members_to_remove = vec![
    "1111111111@s.whatsapp.net".parse()?,
];

let responses = client.groups().remove_participants(
    &group_jid,
    &members_to_remove,
).await?;

for response in responses {
    match response.status.as_deref() {
        Some("200") => println!("Removed: {}", response.jid),
        Some("404") => println!("{} is not in the group", response.jid),
        other => println!("Error removing {}: {:?}", response.jid, other),
    }
}
```

See [Groups API reference](/api/groups#remove_participants) for details.

To also remove participants from a community group's linked/child groups, use `remove_participants_including_linked_groups` instead — same signature, but the removal cascades to subgroups. See [Groups API reference](/api/groups#remove_participants_including_linked_groups) for details.

### Promote to admin

```rust theme={null}
let participants = vec!["1234567890@s.whatsapp.net".parse()?];

let results = client.groups().promote_participants(
    &group_jid,
    &participants,
).await?;

for result in results {
    println!("Promoted {}: status {:?}", result.jid, result.status);
}
```

See [Groups API reference](/api/groups#promote_participants) for details.

### Demote admin

```rust theme={null}
let participants = vec!["1234567890@s.whatsapp.net".parse()?];

let results = client.groups().demote_participants(
    &group_jid,
    &participants,
).await?;

for result in results {
    println!("Demoted {}: status {:?}", result.jid, result.status);
}
```

See [Groups API reference](/api/groups#demote_participants) for details.

### Leave group

```rust theme={null}
client.groups().leave(&group_jid).await?;
println!("Left the group");
```

See [Groups API reference](/api/groups#leave) for details.

## Group invite links

### Get invite link

```rust theme={null}
// Get existing invite link
let link = client.groups().get_invite_link(&group_jid, false).await?;
println!("Invite link: https://chat.whatsapp.com/{}", link);

// Reset and get new invite link
let new_link = client.groups().get_invite_link(&group_jid, true).await?;
println!("New invite link: https://chat.whatsapp.com/{}", new_link);
```

See [Groups API reference](/api/groups#get_invite_link) for details.

<Warning>
  Resetting the invite link (`reset = true`) invalidates the old link. Anyone with the old link will no longer be able to join.
</Warning>

### Join a group via invite

You can join a group using an invite code or a full `https://chat.whatsapp.com/...` URL. The method automatically strips the URL prefix if present.

```rust theme={null}
use whatsapp_rust::features::groups::JoinGroupResult;

// Join using a full URL
let result = client.groups()
    .join_with_invite_code("https://chat.whatsapp.com/AbCdEfGh")
    .await?;

match &result {
    JoinGroupResult::Joined(jid) => {
        println!("Successfully joined group: {}", jid);
    }
    JoinGroupResult::PendingApproval(jid) => {
        println!("Request sent — waiting for admin approval in group: {}", jid);
    }
}
```

If the group has [membership approval](#membership-approval-mode) enabled, the result will be `PendingApproval` instead of `Joined`.

See [Groups API reference](/api/groups#join_with_invite_code) for details.

### Accept a V4 invite message

V4 invites are sent directly by a group admin as a `GroupInviteMessage`, rather than shared as a URL. Use `join_with_invite_v4` to accept these invites:

```rust theme={null}
use whatsapp_rust::features::groups::JoinGroupResult;

let group_jid: Jid = "120363012345678@g.us".parse()?;
let admin_jid: Jid = "15551234567@s.whatsapp.net".parse()?;

let result = client.groups().join_with_invite_v4(
    &group_jid,
    "AbCdEfGh",       // invite code from the message
    1735689600,         // expiration timestamp (Unix seconds)
    &admin_jid,
).await?;

match &result {
    JoinGroupResult::Joined(jid) => {
        println!("Successfully joined group: {}", jid);
    }
    JoinGroupResult::PendingApproval(jid) => {
        println!("Request sent — waiting for admin approval in group: {}", jid);
    }
}
```

<Note>
  V4 invites have an expiration timestamp. The method automatically checks whether the invite has expired and returns an error if it has. Pass `0` as the expiration to skip the check.
</Note>

See [Groups API reference](/api/groups#join_with_invite_v4) for details.

### Preview a group before joining

Use `get_invite_info` to fetch group metadata from an invite code without joining:

```rust theme={null}
let metadata = client.groups().get_invite_info("AbCdEfGh").await?;

println!("Group: {}", metadata.subject);
println!("Members: {}", metadata.participants.len());
println!("Requires approval: {}", metadata.membership_approval);
```

See [Groups API reference](/api/groups#get_invite_info) for details.

## Membership requests

When a group has membership approval enabled, new members must be approved by an admin. You can view, approve, and reject pending requests.

### Get pending requests

```rust theme={null}
let requests = client.groups().get_membership_requests(&group_jid).await?;

for request in &requests {
    println!("Pending: {} (requested at {:?})", request.jid, request.request_time);
}
```

See [Groups API reference](/api/groups#get_membership_requests) for details.

### Approve or reject requests

```rust theme={null}
// Approve specific requests
let to_approve = vec!["15551234567@s.whatsapp.net".parse()?];
let results = client.groups()
    .approve_membership_requests(&group_jid, &to_approve)
    .await?;

for result in &results {
    println!("Approved {}: status {:?}", result.jid, result.status);
}

// Reject specific requests
let to_reject = vec!["15559876543@s.whatsapp.net".parse()?];
client.groups()
    .reject_membership_requests(&group_jid, &to_reject)
    .await?;
```

See [Groups API reference](/api/groups#approve_membership_requests) for details.

<Note>
  You must be a group admin to view, approve, or reject membership requests.
</Note>

### Cancel membership requests

Users can cancel their own pending membership requests:

```rust theme={null}
let my_jid: Jid = "15551234567@s.whatsapp.net".parse()?;
let results = client.groups()
    .cancel_membership_requests(&group_jid, &[my_jid])
    .await?;
```

See [Groups API reference](/api/groups#cancel_membership_requests) for details.

### Revoke invitation codes

Admins can revoke invitation codes from specific participants:

```rust theme={null}
let to_revoke = vec!["15551234567@s.whatsapp.net".parse()?];
let results = client.groups()
    .revoke_request_code(&group_jid, &to_revoke)
    .await?;
```

See [Groups API reference](/api/groups#revoke_request_code) for details.

## Batch operations

### Batch query group info

Query metadata for multiple groups in a single request (up to 10,000 groups):

```rust theme={null}
use whatsapp_rust::features::groups::BatchGroupResult;

let group_jids: Vec<Jid> = vec![
    "120363012345678@g.us".parse()?,
    "120363087654321@g.us".parse()?,
];

let results = client.groups().batch_get_info(group_jids).await?;

for result in results {
    match result {
        BatchGroupResult::Full(metadata) => {
            println!("Group: {} - {}", metadata.id, metadata.subject);
        }
        BatchGroupResult::Truncated { id, size } => {
            println!("Truncated info: {} (size: {:?})", id, size);
        }
        BatchGroupResult::Forbidden(id) => {
            println!("Access denied: {}", id);
        }
        BatchGroupResult::NotFound(id) => {
            println!("Not found: {}", id);
        }
    }
}
```

See [Groups API reference](/api/groups#batch_get_info) for details.

### Batch fetch profile pictures

Fetch profile pictures for multiple groups at once (up to 1,000 groups):

```rust theme={null}
use whatsapp_rust::features::groups::{PictureType, GroupProfilePicture};

let group_jids: Vec<Jid> = vec![
    "120363012345678@g.us".parse()?,
    "120363087654321@g.us".parse()?,
];

let pictures = client.groups()
    .get_profile_pictures(group_jids, PictureType::Preview)
    .await?;

for pic in pictures {
    if let Some(url) = &pic.url {
        println!("Group {}: {}", pic.group_jid, url);
    }
}
```

See [Groups API reference](/api/groups#get_profile_pictures) for details.

### Set or remove the group picture

Admins can update the group's profile picture by uploading JPEG bytes, or remove it with a dedicated call:

```rust theme={null}
use std::fs;

let group_jid: Jid = "120363012345678@g.us".parse()?;

// Set the picture (caller is responsible for sizing/cropping; WhatsApp uses 640x640)
let image_bytes = fs::read("group_avatar.jpg")?;
client.groups().set_profile_picture(&group_jid, image_bytes).await?;

// Remove the picture
client.groups().remove_profile_picture(&group_jid).await?;
```

See [Groups API reference](/api/groups#set_profile_picture) for details.

## Group settings

### Member add mode

Control who can add new members:

```rust theme={null}
use whatsapp_rust::features::groups::MemberAddMode;

pub enum MemberAddMode {
    AdminAdd,      // Only admins can add members
    AllMemberAdd,  // All members can add others
}

// Set during creation
let options = GroupCreateOptions::builder()
    .subject("My Group")
    .member_add_mode(MemberAddMode::AdminAdd)
    .build();

// Or update an existing group
client.groups().set_member_add_mode(&group_jid, MemberAddMode::AdminAdd).await?;
```

See [Groups API reference](/api/groups#set_member_add_mode) for details.

### Membership approval mode

Require admin approval for new members:

```rust theme={null}
use whatsapp_rust::features::groups::MembershipApprovalMode;

pub enum MembershipApprovalMode {
    On,   // Require approval
    Off,  // Auto-accept
}

// Set during creation
let options = GroupCreateOptions::builder()
    .subject("My Group")
    .membership_approval_mode(MembershipApprovalMode::On)
    .build();

// Or update an existing group
client.groups().set_membership_approval(&group_jid, MembershipApprovalMode::On).await?;
```

See [Groups API reference](/api/groups#set_membership_approval) for details.

### Announcement mode

Toggle announcement mode on an existing group (only admins can send messages):

```rust theme={null}
// Enable announcement mode
client.groups().set_announce(&group_jid, true).await?;

// Disable announcement mode
client.groups().set_announce(&group_jid, false).await?;
```

See [Groups API reference](/api/groups#set_announce) for details.

### Frequently-forwarded messages

Restrict or allow frequently-forwarded messages in the group:

```rust theme={null}
// Restrict frequently-forwarded messages
client.groups().set_no_frequently_forwarded(&group_jid, true).await?;

// Allow frequently-forwarded messages
client.groups().set_no_frequently_forwarded(&group_jid, false).await?;
```

See [Groups API reference](/api/groups#set_no_frequently_forwarded) for details.

### Admin reports

Enable or disable admin reports in the group:

```rust theme={null}
// Enable admin reports
client.groups().set_allow_admin_reports(&group_jid, true).await?;

// Disable admin reports
client.groups().set_allow_admin_reports(&group_jid, false).await?;
```

See [Groups API reference](/api/groups#set_allow_admin_reports) for details.

### Group history sharing

Enable or disable sharing group history with new members:

```rust theme={null}
// Enable group history
client.groups().set_group_history(&group_jid, true).await?;

// Disable group history
client.groups().set_group_history(&group_jid, false).await?;
```

See [Groups API reference](/api/groups#set_group_history) for details.

### Member link mode

Control who can share invite links. This setting is updated via the MEX protocol:

```rust theme={null}
use whatsapp_rust::features::groups::MemberLinkMode;

// Only admins can share invite links
client.groups().set_member_link_mode(&group_jid, MemberLinkMode::AdminLink).await?;

// All members can share invite links
client.groups().set_member_link_mode(&group_jid, MemberLinkMode::AllMemberLink).await?;
```

See [Groups API reference](/api/groups#set_member_link_mode) for details.

### Message history sharing mode

Control who can share message history with new members. This setting is updated via the MEX protocol:

```rust theme={null}
use whatsapp_rust::features::groups::MemberShareHistoryMode;

// Only admins can share history
client.groups().set_member_share_history_mode(
    &group_jid,
    MemberShareHistoryMode::AdminShare,
).await?;

// All members can share history
client.groups().set_member_share_history_mode(
    &group_jid,
    MemberShareHistoryMode::AllMemberShare,
).await?;
```

See [Groups API reference](/api/groups#set_member_share_history_mode) for details.

### Limit sharing

Enable or disable limit sharing in the group. This setting is updated via the MEX protocol:

```rust theme={null}
// Enable limit sharing
client.groups().set_limit_sharing(&group_jid, true).await?;

// Disable limit sharing
client.groups().set_limit_sharing(&group_jid, false).await?;
```

See [Groups API reference](/api/groups#set_limit_sharing) for details.

### Member label

Set or clear the bot's per-group member label. This is sent as a message (`ProtocolMessage`), not an IQ, and returns the sent message's ID:

```rust theme={null}
let message_id = client.groups().update_member_label_with_id(&group_jid, "VIP").await?;
println!("Label update sent as message {}", message_id);
```

See [Groups API reference](/api/groups#update_member_label_with_id) for details.

## Privacy tokens on group operations

When server-side A/B experiment flags are enabled, the library automatically attaches privacy tokens (`tc_token`) to participants during group creation and participant addition. This matches WhatsApp Web's behavior and requires no changes to your code.

The following AB prop flags control this behavior:

| Flag                                     | Effect                                                                |
| ---------------------------------------- | --------------------------------------------------------------------- |
| `PRIVACY_TOKEN_ON_GROUP_CREATE`          | Attaches tokens to participants when creating a group                 |
| `PRIVACY_TOKEN_ON_GROUP_PARTICIPANT_ADD` | Attaches tokens to participants when adding them to a group           |
| `PRIVACY_TOKEN_ONLY_CHECK_LID`           | Only resolves tokens via LID mappings, skipping phone number fallback |

These flags are fetched from the server automatically on each connection via `fetch_props()`. Token resolution uses the LID-to-phone-number cache and the `tc_token` store — if a valid, non-expired token exists for a participant, it is attached to the IQ request.

<Note>
  Privacy token attachment is fully automatic. You don't need to call any extra methods or manage tokens manually. If the AB flags are disabled on the server, group operations work exactly as before.
</Note>

See [Client API - AB props cache](/api/client#ab-props-cache) for more details on experiment flags, and [TC Token API](/api/tctoken) for token management.

## Addressing modes

Groups can use different addressing modes:

```rust theme={null}
use wacore::types::message::AddressingMode;

pub enum AddressingMode {
    Pn,   // Phone number (legacy)
    Lid,  // Long ID (new privacy mode)
}

// Check the group's addressing mode
let info = client.groups().query_info(&group_jid).await?;
match info.addressing_mode {
    AddressingMode::Pn => println!("Group uses phone numbers"),
    AddressingMode::Lid => println!("Group uses LIDs (privacy mode)"),
}
```

<Note>
  LID (Long ID) mode provides better privacy by hiding phone numbers. The library automatically handles LID-to-phone-number mapping when needed.
</Note>

## Participant response codes

When adding or removing participants, check the response codes:

```rust theme={null}
use whatsapp_rust::features::groups::ParticipantChangeResponse;

let responses = client.groups().add_participants(&group_jid, &participants).await?;

for response in responses {
    match response.status.as_deref() {
        Some("200") => println!("Success: {}", response.jid),
        Some("403") => println!("Permission denied: {}", response.jid),
        Some("404") => println!("Not found: {}", response.jid),
        Some("409") => println!("Already in group: {}", response.jid),
        other => println!("Unknown status for {}: {:?}", response.jid, other),
    }
    
    if let Some(error) = &response.error {
        println!("Error: {}", error);
    }
}
```

## Error handling

```rust theme={null}
use anyhow::Result;

async fn create_group_safely(
    client: &Client,
    subject: &str,
    participants: Vec<Jid>,
) -> Result<Jid> {
    let options = GroupCreateOptions::builder()
        .subject(subject)
        .participants(
            participants
                .into_iter()
                .map(GroupParticipantOptions::new)
                .collect(),
        )
        .build();
    
    match client.groups().create_group(options).await {
        Ok(result) => {
            println!("✅ Group created: {}", result.gid);
            Ok(result.gid)
        }
        Err(e) => {
            eprintln!("❌ Failed to create group: {:?}", e);
            Err(e)
        }
    }
}
```

## Advanced usage

### Handling LID groups

For LID-based groups, you may need phone number mappings:

```rust theme={null}
let info = client.groups().query_info(&group_jid).await?;

if info.addressing_mode == AddressingMode::Lid {
    // Look up phone number for each LID participant
    for participant in &info.participants {
        if let Some(phone_jid) = info.phone_jid_for_lid_user(&participant.user) {
            println!("LID {} maps to phone {}", participant, phone_jid);
        }
    }
}
```

### Participant options

For advanced participant configurations:

```rust theme={null}
use whatsapp_rust::features::groups::GroupParticipantOptions;
use wacore_binary::jid::Jid;

let lid_jid: Jid = "123456789012345:10@lid".parse()?;
let phone_jid: Jid = "1234567890@s.whatsapp.net".parse()?;

let participant = GroupParticipantOptions::new(lid_jid)
    .with_phone_number(phone_jid);

// The library will automatically resolve phone numbers for LID participants
```

See [Groups API reference](/api/groups) for addressing mode details.

## Best practices

<Steps>
  ### Validate input before creating groups

  ```rust theme={null}
  // ✅ Good: Validate before creation
  let subject = match GroupSubject::new(user_input) {
      Ok(s) => s,
      Err(e) => {
          eprintln!("Invalid subject: {}", e);
          return Err(e);
      }
  };

  // ❌ Bad: No validation
  let subject = GroupSubject::new(user_input)?;  // May panic on invalid input
  ```

  ### Check response codes

  Always check participant operation responses:

  ```rust theme={null}
  let responses = client.groups().add_participants(&group_jid, &participants).await?;

  let mut success_count = 0;
  let mut failed = Vec::new();

  for response in responses {
      if response.status.as_deref() == Some("200") {
          success_count += 1;
      } else {
          failed.push(response);
      }
  }

  println!("Added {} participants", success_count);
  if !failed.is_empty() {
      eprintln!("Failed to add {} participants", failed.len());
  }
  ```

  ### Handle addressing modes

  Be aware of LID vs PN addressing:

  ```rust theme={null}
  let info = client.groups().query_info(&group_jid).await?;

  if info.addressing_mode == AddressingMode::Lid {
      // Handle LID-based group
      // Phone numbers may not be directly visible
  } else {
      // Handle phone-number-based group
  }
  ```

  ### Cache group information

  The library automatically caches group info:

  ```rust theme={null}
  // First call: fetches from server
  let info = client.groups().query_info(&group_jid).await?;

  // Second call: uses cache
  let info = client.groups().query_info(&group_jid).await?;
  ```
</Steps>

## Next steps

* [Community management](/guides/communities) - Create and manage communities with linked subgroups
* [Sending messages](/guides/sending-messages) - Send messages to groups
* [Receiving messages](/guides/receiving-messages) - Handle group message events
* [Custom backends](/guides/custom-backends) - Store group metadata
