Group management
Create and manage groups from your server. Groups have fixed members and suit class groups, project groups and interest groups. You can create groups from your own business relationships, choosing the owner and initial members, who join directly without having to agree; you can also query and change any group in the app, and ban or dissolve groups that break the rules.
For example, create a parents' group for a class with zhangsan as owner:
curl -X POST "$IM_API/$ORG/$APP/groups" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "owner": "zhangsan", "name": "三年级二班家长群", "members": ["lisi", "wangwu"], "attributes": { "class_id": "C-302" } }'The group_id in the response is also the group conversation's ID, so you can use it right away to send messages.
| You want to | See |
|---|---|
| Create groups, look them up, change their profile | This page: Create a group, List groups, Update a group |
| Transfer ownership, mute everyone, ban, dissolve | This page: Transfer ownership, Turn on mute-all, Ban a group, Dissolve a group |
| Add or remove people, set admins, mute members, change group nicknames | Group members |
| Keep someone out of a group | Group block list |
| Users applying to join or inviting others from clients | Join requests and invitations |
| Which groups a user is in, and their group settings | A user's groups |
The server isn't bound by group roles
With the App Token you act as the app's administrator: you can change any group and add or remove any member, regardless of owner or admin roles. Only a few rules apply to the server too: the owner only changes through Transfer ownership, and the owner can't be removed, muted or put on the group block list; transfer ownership first if you need to deal with the owner.
Creating groups isn't idempotent
Retrying a create request after a timeout may create two identical groups. Put your own business ID (such as a class ID) in the group's custom attributes, and before retrying, list groups by owner to confirm the earlier attempt didn't succeed.
While the app is read-only (see Rate limits and app status), creating groups, adding members and changing group or member profiles return 403 app_unavailable; removing members, muting, mute-all, the group block list, transferring ownership, setting admins, banning and unbanning, and dissolving still work.
Concepts
Group types
| Type | type | Description |
|---|---|---|
| Private | private | The default. People join only by member invitation, invite link or server addition, and non-members can't see the group in clients. Good for colleague or parent groups |
| Public | public | Users can find it in clients, see its name, avatar, description and size, and apply to join; members can invite people too. Good for interest or fan groups |
Groups can switch between the two types after creation. Turning a public group private invalidates all pending join applications, and they don't come back if it turns public again; turning a private group public sets applications to require approval by default.
Member roles
| Role | role | Description |
|---|---|---|
| Owner | owner | One per group. Can do every management action, including setting admins, transferring ownership and dissolving the group. Can't be removed, muted or put on the group block list; must transfer ownership before leaving |
| Admin | admin | Up to 20 per group, set by the owner. Can change the group's profile and settings (except its type), approve join applications, remove and mute regular members, manage the group block list and turn on mute-all |
| Member | member | Can post and change their own group nickname; whether they can invite others depends on the member_invite setting |
These are permissions in clients; server APIs aren't bound by them.
When a user is deleted, they're removed from every group automatically. If they owned a group, ownership goes to the earliest-joined admin, or the earliest-joined regular member if there are no admins; a group with nobody else in it is dissolved.
Ways to join
Each member's joined_via records how they joined:
joined_via | Way |
|---|---|
create | Joined at creation: the owner and the initial members given when creating |
server | Added directly by the server or console, see Add group members |
invite | Invited by a member from a client. Whether the invitee must confirm depends on their group settings |
apply | Applied to a public group from a client, joining directly or after owner or admin approval depending on the group's application mode |
link | Joined through an invite link (or QR code) created by the owner or an admin; works for private groups too |
Whichever way, these must hold: the group is normal (not banned or dissolved), the user isn't on the group block list, the group isn't full, and the user hasn't reached their group limit. For the full application and invitation flows, see Join requests and invitations.
Group settings
| Field | Values | Description |
|---|---|---|
member_invite | free (default), approval, disabled | Whether regular members can invite others: free directly; approval with owner or admin approval; disabled not at all. The owner and admins aren't limited by this |
join_mode | approval (default), free | How public groups handle applications: approval needs owner or admin approval; free joins on applying. Private groups can't be applied to, so it's null and can't be set |
mute_all | true, false | Mute-all: only the owner and admins can post from clients, see Turn on mute-all |
max_members | 2 to 5000 | The group's size limit (owner included). The app default is max_group_members in the runtime policy (500 by default), capped by the group-size quota of the app's plan; without a group-specific value the app default applies, otherwise the smaller of the two. Only the server and console can set it. Lowering it below the current size doesn't remove anyone; it just stops new members |
Group status
status | Description |
|---|---|
active | Normal |
disabled | Banned: members stay, but nobody can post or join, see Ban a group |
dismissed | Dissolved, permanently, see Dissolve a group |
Versions
Groups have two versions, each incremented on change:
info_version: the version of the group profile and settings. Changing them, transferring ownership, turning mute-all on or off, banning, unbanning and dissolving all increment it. When updating a group, send theinfo_versionyou read (asversion) to avoid overwriting someone else's simultaneous change, see Concurrent changes.member_version: the member list version. Incremented when members join or leave, or a member's role, group nickname, attributes or mute status changes. When listing group members, send the version you saved and no list is returned if nothing changed.
Group avatars
The group avatar avatar_url can be stored by this service or use your own image address.
Using this service's avatars: upload the image with purpose group_avatar (you can do this before creating the group) to get a public address anyone can open (long edge scaled to at most 640 pixels), and put it in avatar_url when creating or updating the group. Avatar files are kept based on whether a group is using them:
| Case | File |
|---|---|
| No group used it within 24 hours of upload | Deleted |
| Replaced (changed to another address or cleared) | Deleted after 7 days |
| Several groups use the same file | Only the first group to use it counts |
| The group is dissolved | Kept; dissolved groups still show their name and avatar |
Using your own addresses: avatar_url written through server APIs only has its format checked. But when members create a group or change its avatar from a client and the app enables media_url_only in its runtime policy, only this app's avatar addresses or https addresses on hosts in media_allowed_hosts are allowed; otherwise you get 400 invalid_argument (url_not_allowed, details.field avatar_url).
Group files
Group files are files shared by members, listed in the group newest first. Unlike message attachments, they don't expire by default, so they suit material you want to keep.
| Clients (group members) | Your server | |
|---|---|---|
| Upload | Purpose group_file (images, videos or files); not while the group is banned or when the app turns off group_file_enabled | Upload with purpose group_file and the group_id, regardless of membership, group_file_enabled or bans; 404 not_found if the group doesn't exist or was dissolved |
| List and download | Only current members; not after leaving | Any group, see Download and manage files |
| Delete | The uploader, the owner and admins | Any group |
- Limit: up to 1000 per group, counted toward the app's storage.
- Retention: kept indefinitely by default; set days with
group_file_retention_daysin the runtime policy. All group files are deleted when the group is dissolved (usually within a minute) and can't be downloaded afterwards.
Create a group
Create a group with an owner and initial members.
- Joining directly: the owner and initial members don't confirm, their group settings are ignored, and the before-join-group callback isn't called (it only runs for group creation, invitations, applications and invite links in clients, see Content checks and the before-join-group callback).
- Individual failures don't stop creation: for example a nonexistent user, someone on the group block list, or someone at their group limit;
resultslists each outcome. - Notifications: the online devices of the owner and initial members are notified in real time, and the group conversation shows creation and join notices.
- Quota: counts toward the app's call quota once per initial member (at least 1), see Rate limits and app status; non-dissolved groups can't exceed the plan's group quota, see Plans and billing.
- Moderation: the name, description, announcement and avatar go through moderation (content from your server is checked against platform rules only by default, see Server-submitted content). If they fail, no group is created and you get
403 content_rejected; text matching replacement rules is saved with the replacement, so rely on the response.
/{org_name}/{app_name}/groupsPath parameters
For org_name and app_name, see the server overview.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
owner | String | Yes | The owner's username; must be an existing user |
type | String | No | private (default) or public |
name | String | No | Group name, up to 64 characters without line breaks or other control characters; leading and trailing whitespace trimmed. Defaults to an empty string |
avatar_url | String | No | Group avatar address starting with http:// or https://, at most 512 bytes, no whitespace. Can be a group avatar from this service or your own, see Group avatars. The server only checks the format and never fetches it |
description | String | No | Group description, up to 512 characters; line breaks allowed |
announcement | String | No | Group announcement, up to 2048 characters; line breaks allowed |
attributes | Object | No | Custom attributes, string key-value pairs visible to all members, for things like your business ID or group category. Up to 32 entries and 4 KB of JSON; keys are 1 to 32 characters of letters, digits and _, -, .; values are strings |
member_invite | String | No | Whether regular members can invite others: free (default), approval or disabled, see Group settings |
join_mode | String | No | How a public group handles applications: approval (default) or free. Can't be set for private groups |
max_members | Number | No | The group's own size limit, 2 to 5000; omitted or null uses the app default, see Group settings |
members | Array<String> | No | Initial members, up to 100, who join directly with joined_via create. Duplicates are handled once; if it includes the owner, that item's result is already_member |
Request example
curl -X POST "$IM_API/$ORG/$APP/groups" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"owner": "zhangsan",
"type": "private",
"name": "三年级二班家长群",
"description": "家校沟通",
"announcement": "本周五下午家长会",
"attributes": { "class_id": "C-302" },
"member_invite": "disabled",
"max_members": 200,
"members": ["lisi", "wangwu", "nobody", "zhangsan"]
}'Response
On success you get 201 Created with a group object plus one field:
| Field | Type | Description |
|---|---|---|
results | Array<Object> | Each initial member's result in request order, see Batch results. Empty if there were no initial members |
{
"group_id": "99582624883802112",
"type": "private",
"name": "三年级二班家长群",
"avatar_url": "",
"description": "家校沟通",
"announcement": "本周五下午家长会",
"announcement_updated_at": "2026-10-02T19:05:47.929Z",
"announcement_updated_by": null,
"attributes": {
"class_id": "C-302"
},
"owner": "zhangsan",
"member_invite": "disabled",
"join_mode": null,
"mute_all": false,
"max_members": 200,
"member_count": 3,
"status": "active",
"disabled_by": null,
"info_version": 1,
"member_version": 2,
"created_at": "2026-10-02T19:05:47.929Z",
"status_reason": null,
"max_members_setting": 200,
"created_via": "openapi",
"dismissed_at": null,
"results": [
{ "username": "lisi", "status": "joined" },
{ "username": "wangwu", "status": "joined" },
{ "username": "nobody", "code": "not_found", "message": "用户不存在" },
{ "username": "zhangsan", "status": "already_member" }
]
}Errors
| HTTP status | code | Description |
|---|---|---|
| 400 | invalid_argument | owner is missing; a field has an invalid value; join_mode was set for a private group; members has more than 100 entries |
| 403 | app_unavailable | The app is read-only and can't create groups |
| 403 | content_rejected | The group profile failed moderation; details.field is name, description, announcement or avatar_url and details.reason gives the reason, see Errors callers see |
| 404 | not_found | The owner user doesn't exist |
| 409 | limit_exceeded | details.reason user_group_limit: the owner has reached their group limit (max_groups_per_user in the runtime policy, 500 by default, capped by the plan); no group is created |
| 409 | limit_exceeded | details.reason app_group_limit: the app's non-dissolved groups have reached the plan's group quota, see Plans and billing |
List groups
List the app's groups page by page, newest first, optionally filtered by type, status and owner, or searched by name prefix. Dissolved groups are included; filter them out with status.
/{org_name}/{app_name}/groupsPath parameters
For org_name and app_name, see the server overview.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
type | String | No | Only this type: private or public |
status | String | No | Only this status: active, disabled or dismissed |
owner | String | No | Only groups owned by this user; an empty list if the user doesn't exist |
name_prefix | String | No | Search by name prefix, case-insensitive; % and _ match literally |
limit | Number | No | Page size, default 20, 1 to 100 |
cursor | String | No | The cursor for the next page, see Paging |
Request example
curl -X GET "$IM_API/$ORG/$APP/groups?owner=zhangsan&status=active&limit=20" \
-H "Authorization: Bearer $APP_TOKEN"Response
On success you get 200 OK, with each item in items a group object and the next page's cursor in next_cursor (null when there's no next page).
{
"items": [
{
"group_id": "99582624883802112",
"type": "private",
"name": "三年级二班家长群",
"avatar_url": "https://cdn.example.com/group/c302.png",
"description": "家校沟通",
"announcement": "家长会改到周六上午 9 点,请准时参加",
"announcement_updated_at": "2026-10-02T19:16:49.151Z",
"announcement_updated_by": null,
"attributes": {
"class_id": "C-302",
"term": "2026-autumn"
},
"owner": "zhangsan",
"member_invite": "disabled",
"join_mode": null,
"mute_all": false,
"max_members": 500,
"member_count": 3,
"status": "active",
"disabled_by": null,
"info_version": 17,
"member_version": 18,
"created_at": "2026-10-02T19:05:47.929Z",
"status_reason": null,
"max_members_setting": null,
"created_via": "openapi",
"dismissed_at": null
}
],
"next_cursor": null
}Errors
| HTTP status | code | Description |
|---|---|---|
| 400 | invalid_argument | type or status has an invalid value, or limit is out of range |
Get a group
Return everything about a group. Dissolved groups can be queried too, with status dismissed.
/{org_name}/{app_name}/groups/{group_id}Path parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
group_id | String | The group ID |
Request example
curl -X GET "$IM_API/$ORG/$APP/groups/99582624883802112" \
-H "Authorization: Bearer $APP_TOKEN"Response
On success you get 200 OK with a group object.
{
"group_id": "99582624883802112",
"type": "private",
"name": "三年级二班家长群",
"avatar_url": "https://cdn.example.com/group/c302.png",
"description": "家校沟通",
"announcement": "家长会改到周六上午 9 点,请准时参加",
"announcement_updated_at": "2026-10-02T19:16:49.151Z",
"announcement_updated_by": null,
"attributes": {
"class_id": "C-302",
"term": "2026-autumn"
},
"owner": "zhangsan",
"member_invite": "disabled",
"join_mode": null,
"mute_all": false,
"max_members": 500,
"member_count": 3,
"status": "active",
"disabled_by": null,
"info_version": 17,
"member_version": 18,
"created_at": "2026-10-02T19:05:47.929Z",
"status_reason": null,
"max_members_setting": null,
"created_via": "openapi",
"dismissed_at": null
}Errors
| HTTP status | code | Description |
|---|---|---|
| 404 | not_found | The group doesn't exist, or group_id is malformed |
Update a group's profile and settings
Change the group's name, avatar, description, announcement, custom attributes and settings. Only fields in the request change.
- Notifications: the group's online members are notified in real time; changing the name or announcement adds a notice to the group conversation.
- Banned groups can be updated, so violating names, announcements and avatars can be cleared.
- The owner can't be changed here; use Transfer ownership.
- Moderation: only names, descriptions, announcements and avatars that changed and aren't empty are checked. If they fail, nothing changes and you get
403 content_rejected; text matching replacement rules is saved with the replacement.
/{org_name}/{app_name}/groups/{group_id}Path parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
group_id | String | The group ID |
Request body
At least one field to change. Formats are the same as in Create a group.
| Field | Type | Required | Description |
|---|---|---|---|
type | String | No | private or public. Turning a public group private sets join_mode to null and invalidates pending applications; turning a private group public sets join_mode to approval by default, which you can override in the same request |
name | String | No | Group name, up to 64 characters; an empty string clears it |
avatar_url | String | No | Group avatar address; an empty string clears it. After replacing or clearing an avatar from this service, the old file is deleted after 7 days, see Group avatars |
description | String | No | Group description, up to 512 characters |
announcement | String | No | Group announcement, up to 2048 characters. announcement_updated_at becomes the current time when it changes |
attributes | Object | No | Merged entry by entry: keys present are added or overwritten, keys set to null are deleted, keys absent are unchanged. null for the whole field clears everything. The merged result must stay within the entry and size limits |
member_invite | String | No | Whether regular members can invite others: free, approval or disabled |
join_mode | String | No | How a public group handles applications: approval or free. Can't be set for private groups |
max_members | Number | No | The group's own size limit, 2 to 5000; null clears it so the app default applies |
version | Number | No | The info_version you read. If given and it doesn't match the current info_version, you get 409 version_conflict and nothing changes |
Request example
curl -X PATCH "$IM_API/$ORG/$APP/groups/99582624883802112" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "三年级二班家长群",
"announcement": "家长会改到周六上午 9 点,请准时参加",
"attributes": { "term": "2026-autumn", "grade": null },
"max_members": null,
"version": 16
}'Response
On success you get 200 OK with the updated group object plus one field:
| Field | Type | Description |
|---|---|---|
changed | Boolean | Whether this request changed the group. false when every value equals the old one, in which case info_version doesn't change and members aren't notified |
{
"group_id": "99582624883802112",
"type": "private",
"name": "三年级二班家长群",
"avatar_url": "https://cdn.example.com/group/c302.png",
"description": "家校沟通",
"announcement": "家长会改到周六上午 9 点,请准时参加",
"announcement_updated_at": "2026-10-02T19:16:49.151Z",
"announcement_updated_by": null,
"attributes": {
"class_id": "C-302",
"term": "2026-autumn"
},
"owner": "zhangsan",
"member_invite": "disabled",
"join_mode": null,
"mute_all": false,
"max_members": 500,
"member_count": 3,
"status": "active",
"disabled_by": null,
"info_version": 17,
"member_version": 18,
"created_at": "2026-10-02T19:05:47.929Z",
"status_reason": null,
"max_members_setting": null,
"created_via": "openapi",
"dismissed_at": null,
"changed": true
}Errors
| HTTP status | code | Description |
|---|---|---|
| 400 | invalid_argument | Nothing to change; a field has an invalid value; join_mode was set for a private group; the request contains a field that can't be changed (such as owner) |
| 403 | app_unavailable | The app is read-only and group profiles can't be changed |
| 403 | content_rejected | The new group profile failed moderation; details.field is name, description, announcement or avatar_url |
| 404 | not_found | The group doesn't exist or was dissolved |
| 409 | version_conflict | version doesn't match the current info_version; query again before deciding whether to change it |
Transfer ownership
Make another member the owner. Afterwards:
| Who | What changes |
|---|---|
| The old owner | Becomes a regular member; invite links they created stop working |
| The new owner | No longer uses an admin slot if they were an admin; any mute on them is lifted |
| The group | info_version and member_version each increase by one; online members are notified in real time and the group conversation shows an owner-change notice |
Banned groups can transfer ownership too, so you can deal with an owner who broke the rules.
/{org_name}/{app_name}/groups/{group_id}/ownerPath parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
group_id | String | The group ID |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
username | String | Yes | The new owner's username; must be a member of the group. If it's the current owner, nothing changes and changed is false |
Request example
curl -X PUT "$IM_API/$ORG/$APP/groups/99582624883802112/owner" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"username": "wangwu"
}'Response
On success you get 200 OK with the group object after the transfer, plus changed with the same meaning as in Update a group.
{
"group_id": "99582624883802112",
"type": "private",
"name": "三年级二班家长群",
"avatar_url": "https://cdn.example.com/group/c302.png",
"description": "家校沟通",
"announcement": "家长会改到周六上午 9 点,请准时参加",
"announcement_updated_at": "2026-10-02T19:16:49.151Z",
"announcement_updated_by": null,
"attributes": {
"class_id": "C-302",
"term": "2026-autumn"
},
"owner": "wangwu",
"member_invite": "disabled",
"join_mode": null,
"mute_all": false,
"max_members": 500,
"member_count": 3,
"status": "active",
"disabled_by": null,
"info_version": 18,
"member_version": 19,
"created_at": "2026-10-02T19:05:47.929Z",
"status_reason": null,
"max_members_setting": null,
"created_via": "openapi",
"dismissed_at": null,
"changed": true
}Errors
| HTTP status | code | Description |
|---|---|---|
| 403 | not_group_member | The user isn't a member of the group |
| 404 | not_found | The group doesn't exist or was dissolved; the username user doesn't exist (also returned when username is omitted) |
Turn on mute-all
With mute-all on, only the owner and admins can post from clients; regular members sending group messages get 403 group_muted. The exemption for the owner and admins doesn't cover individual mutes: an admin who has been muted still can't post.
The group's online members are notified in real time and the group conversation shows a mute-all notice. If it's already on, nothing changes and changed is false. Banned groups can set it too.
提示
Mutes only limit posting from clients. Your server sending messages as a member isn't limited by group mutes or mute-all.
/{org_name}/{app_name}/groups/{group_id}/mute-allPath parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
group_id | String | The group ID |
Request example
curl -X PUT "$IM_API/$ORG/$APP/groups/99582624883802112/mute-all" \
-H "Authorization: Bearer $APP_TOKEN"Response
On success you get 200 OK with a group object plus changed with the same meaning as in Update a group.
{
"group_id": "99582624883802112",
"type": "private",
"name": "三年级二班家长群",
"avatar_url": "https://cdn.example.com/group/c302.png",
"description": "家校沟通",
"announcement": "家长会改到周六上午 9 点,请准时参加",
"announcement_updated_at": "2026-10-02T19:16:49.151Z",
"announcement_updated_by": null,
"attributes": {
"class_id": "C-302",
"term": "2026-autumn"
},
"owner": "wangwu",
"member_invite": "disabled",
"join_mode": null,
"mute_all": true,
"max_members": 500,
"member_count": 3,
"status": "active",
"disabled_by": null,
"info_version": 19,
"member_version": 19,
"created_at": "2026-10-02T19:05:47.929Z",
"status_reason": null,
"max_members_setting": null,
"created_via": "openapi",
"dismissed_at": null,
"changed": true
}Errors
| HTTP status | code | Description |
|---|---|---|
| 404 | not_found | The group doesn't exist or was dissolved |
Turn off mute-all
Turn off mute-all so regular members can post again. Individually muted members still can't post; unmute them separately. If it's not on, nothing changes and changed is false.
/{org_name}/{app_name}/groups/{group_id}/mute-allPath parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
group_id | String | The group ID |
Request example
curl -X DELETE "$IM_API/$ORG/$APP/groups/99582624883802112/mute-all" \
-H "Authorization: Bearer $APP_TOKEN"Response
On success you get 200 OK with the same response as Turn on mute-all, with mute_all false.
Errors
| HTTP status | code | Description |
|---|---|---|
| 404 | not_found | The group doesn't exist or was dissolved |
Ban a group
Temporarily disable a group that breaks the rules; you can unban it later. While banned:
| Can | Can't | |
|---|---|---|
| Members (clients) | View the group and history, leave the group | Post (403 group_disabled), invite, apply, approve, join through invite links, change the group profile or settings, change group nicknames, transfer ownership, set admins |
| Your server | Change the group profile and members' group nicknames (to clear violations), transfer ownership, set admins, remove, mute, manage the group block list, dissolve, send messages to the group | Add members |
Pending join requests and invitations are paused while banned, and unexpired ones become valid again after unbanning.
After banning, status becomes disabled and disabled_by is tenant; the group's online members are notified in real time and the group conversation shows a ban notice.
Groups banned by the platform
Groups with disabled_by platform were banned by the platform for breaking laws or platform rules. You can't unban, dissolve or send messages to them; banning them again doesn't change anything and just returns the current info.
/{org_name}/{app_name}/groups/{group_id}/disablePath parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
group_id | String | The group ID |
Request body
The body is optional.
| Field | Type | Required | Description |
|---|---|---|---|
reason | String | No | The ban reason, up to 256 characters without line breaks or other control characters. Saved in the group object's status_reason, visible only through server APIs and the console, never in clients |
Banning a group you already banned only replaces the reason with the new reason (clearing it if omitted); changed is false, info_version doesn't change and members aren't notified.
Request example
curl -X POST "$IM_API/$ORG/$APP/groups/99582624883802112/disable" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reason": "群公告含违规广告"
}'Response
On success you get 200 OK with the banned group object plus changed with the same meaning as in Update a group.
{
"group_id": "99582624883802112",
"type": "private",
"name": "三年级二班家长群",
"avatar_url": "https://cdn.example.com/group/c302.png",
"description": "家校沟通",
"announcement": "家长会改到周六上午 9 点,请准时参加",
"announcement_updated_at": "2026-10-02T19:16:49.151Z",
"announcement_updated_by": null,
"attributes": {
"class_id": "C-302",
"term": "2026-autumn"
},
"owner": "zhangsan",
"member_invite": "disabled",
"join_mode": null,
"mute_all": false,
"max_members": 500,
"member_count": 3,
"status": "disabled",
"disabled_by": "tenant",
"info_version": 22,
"member_version": 21,
"created_at": "2026-10-02T19:05:47.929Z",
"status_reason": "群公告含违规广告",
"max_members_setting": null,
"created_via": "openapi",
"dismissed_at": null,
"changed": true
}Errors
| HTTP status | code | Description |
|---|---|---|
| 400 | invalid_argument | reason is longer than 256 characters or has control characters |
| 404 | not_found | The group doesn't exist or was dissolved |
Unban a group
Lift your ban so the group returns to normal: members can post again and unexpired join requests and invitations become valid. status becomes active, status_reason is cleared, and online members are notified in real time. If the group isn't banned, nothing changes and changed is false.
/{org_name}/{app_name}/groups/{group_id}/enablePath parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
group_id | String | The group ID |
Request example
curl -X POST "$IM_API/$ORG/$APP/groups/99582624883802112/enable" \
-H "Authorization: Bearer $APP_TOKEN"Response
On success you get 200 OK with the unbanned group object plus changed, in the same structure as Ban a group, with status active and disabled_by and status_reason null.
Errors
| HTTP status | code | Description |
|---|---|---|
| 403 | permission_denied | The group is banned by the platform (disabled_by platform), and only the platform can unban it |
| 404 | not_found | The group doesn't exist or was dissolved |
Dissolve a group
Dissolve a group. This can't be undone. Afterwards:
| Area | Result |
|---|---|
| The group | status becomes dismissed immediately and nobody can join or post; online members are notified in real time and the group conversation shows "Group dissolved" |
| Join requests and invitations | Invalid immediately |
| Members | Get a "Group dissolved" offline push when the app isn't in the foreground; their conversation Do Not Disturb for the group is deleted. Members stay for about an hour, then are removed in batches, member_count drops to 0, and block list and request records are deleted |
| Group files | All deleted (usually within a minute) and can't be downloaded; the group avatar is kept |
| The group record | Kept permanently: you can still get the group and its ID is never reused; it can't be changed, and related APIs return 404 not_found |
Dissolving the same group again also returns 204 No Content.
/{org_name}/{app_name}/groups/{group_id}Path parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
group_id | String | The group ID |
Request body
The body is optional.
| Field | Type | Required | Description |
|---|---|---|---|
reason | String | No | Why it was dissolved, up to 256 characters without control characters. Only recorded in the console's operation log and never shown to members |
Request example
curl -X DELETE "$IM_API/$ORG/$APP/groups/99582553119260672" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reason": "班级已毕业"
}'Response
On success you get 204 No Content with no body. Getting the group afterwards:
{
"group_id": "99582553119260672",
"type": "private",
"name": "三年级二班家长群",
"avatar_url": "",
"description": "家校沟通",
"announcement": "本周五下午家长会",
"announcement_updated_at": "2026-10-02T19:05:30.818Z",
"announcement_updated_by": null,
"attributes": {
"class_id": "C-302"
},
"owner": "zhangsan",
"member_invite": "disabled",
"join_mode": null,
"mute_all": false,
"max_members": 2,
"member_count": 3,
"status": "dismissed",
"disabled_by": null,
"info_version": 3,
"member_version": 2,
"created_at": "2026-10-02T19:05:30.818Z",
"status_reason": null,
"max_members_setting": 2,
"created_via": "openapi",
"dismissed_at": "2026-10-02T19:11:18.070Z"
}Errors
| HTTP status | code | Description |
|---|---|---|
| 400 | invalid_argument | reason is longer than 256 characters or has control characters |
| 403 | permission_denied | The group is banned by the platform (disabled_by platform) and can't be dissolved |
| 404 | not_found | The group doesn't exist |
Data structures
Group object
Group objects from server APIs have all the fields below. The group info clients see doesn't include status_reason, max_members_setting, created_via or dismissed_at.
| Field | Type | Description |
|---|---|---|
group_id | String | The group ID, generated by the system and never changed |
type | String | private or public |
name | String | Group name; empty string if none |
avatar_url | String | Group avatar address; empty string if none |
description | String | Group description; empty string if none |
announcement | String | Group announcement; empty string if none |
announcement_updated_at | String | When the announcement last changed; null if never set |
announcement_updated_by | String | Who last changed the announcement from a client; null when changed by the server or console, or when that person was deleted |
attributes | Object | Custom attributes, string key-value pairs; null if none |
owner | String | The owner's username. Briefly null when the owner's account was just deleted and a new owner hasn't been chosen yet |
member_invite | String | Whether regular members can invite others: free, approval or disabled, see Group settings |
join_mode | String | How a public group handles applications: approval or free; null for private groups |
mute_all | Boolean | Whether mute-all is on |
max_members | Number | The size limit in effect: the smaller of the group's own limit and the app default (itself the smaller of the runtime policy and the plan) |
member_count | Number | Current number of members, owner included |
status | String | active, disabled (banned) or dismissed (dissolved) |
disabled_by | String | Who banned it: tenant you (server or console), platform the platform; null when not banned |
info_version | Number | Version of the group profile and settings, see Versions |
member_version | Number | Member list version |
created_at | String | Creation time |
status_reason | String | Ban reason; may be null. Only returned by server APIs and the console |
max_members_setting | Number | The group's own size limit; null if not set |
created_via | String | How it was created: openapi server API, console, or client by a user in a client |
dismissed_at | String | When it was dissolved; null if not dissolved |
{
"group_id": "99582688326844416",
"type": "public",
"name": "摄影爱好者",
"avatar_url": "",
"description": "分享作品,交流器材",
"announcement": "",
"announcement_updated_at": null,
"announcement_updated_by": null,
"attributes": null,
"owner": "lisi",
"member_invite": "approval",
"join_mode": "approval",
"mute_all": false,
"max_members": 500,
"member_count": 5,
"status": "active",
"disabled_by": null,
"info_version": 12,
"member_version": 5,
"created_at": "2026-10-02T19:06:03.054Z",
"status_reason": null,
"max_members_setting": null,
"created_via": "openapi",
"dismissed_at": null
}