Block list
Users can add people they don't want to hear from to their block list. Blocking is one-way: after A blocks B, B's actions toward A are limited, but A can still message B. Users usually block from clients; your server can manage block lists for them or import them from another system.
For example, block spammer for alice:
curl -X PUT "$IM_API/$ORG/$APP/users/alice/blacklist/spammer" \
-H "Authorization: Bearer $APP_TOKEN"In the path, {username} is the block list's owner (A) and {target} is the blocked user (B).
| After blocking | Details |
|---|---|
| B can't send A one-to-one messages | Sending from a client returns 403 user_blocked; reactions and pins in their one-to-one chat are blocked too, and typing indicators don't reach A. Messages your server sends as B via the REST API aren't limited |
| B can't send A friend requests | 403 user_blocked, see Friend requests |
| B can't invite A to groups | When B invites A from a client (including when creating a group), A's entry fails with user_blocked |
| Friendship isn't ended | If they were friends, B stays in A's friend list; after A unblocks B they can chat again without re-adding |
| A's request to B is withdrawn | A's pending friend request to B is withdrawn and B can no longer accept it. B's request to A isn't affected, and A can still accept or decline it |
| Groups and chat rooms aren't affected | Messages in groups and chat rooms ignore personal block lists |
- The blocked user isn't told: the owner's online devices get
blacklist.changed; the blocked user gets nothing. Queries only answer "did I block them", never "did they block me". - Limit: up to 1000 blocked users each.
- Enforcement switch: when
user_blacklist_enabledin the runtime policy (on by default, see Runtime policy) is off, block lists are kept but none of the actions above are blocked; users can't block others from clients (403 permission_denied) but can still view and unblock. The server REST API ignores the switch, so you can import data before turning enforcement on. - Deleted users are removed from everyone's block lists automatically.
- Safe to retry: blocking and unblocking return
changedandblacklist_version(the list's version, which increases by 1 with each change). Cases with no change, such as blocking again, return200 OKwithchangedfalse.
Get the block list
Get a user's block list page by page, 100 per page by default and up to 500.
/{org_name}/{app_name}/users/{username}/blacklistPath parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
username | String | The block list's owner |
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | Number | No | Page size, default 100, 1 to 500 |
cursor | String | No | The cursor for the next page; omit for the first page, see Paging |
known_version | Number | No | The block list version you saved, a non-negative integer, only used for the first page. If it equals the current version, only the list header is returned (not_modified true), without items or next_cursor |
Request example
curl "$IM_API/$ORG/$APP/users/bob/blacklist" \
-H "Authorization: Bearer $APP_TOKEN"Response
On success you get 200 OK:
| Field | Type | Description |
|---|---|---|
version | Number | The list's current version; 0 for users who never blocked anyone |
not_modified | Boolean | Whether it equals known_version from the request. When true, the response has only version, not_modified, count and max_count |
count | Number | Current number of blocked users |
max_count | Number | The block list limit, always 1000 |
items | Array<Object> | This page's entries, each a block list entry |
next_cursor | String | The next page's cursor; null when there's no next page |
{
"version": 4,
"not_modified": false,
"count": 2,
"max_count": 1000,
"items": [
{ "username": "dave", "nickname": "戴夫", "avatar_url": "", "created_at": "2026-10-02T19:10:16.494Z" },
{ "username": "erin", "nickname": "艾琳", "avatar_url": "", "created_at": "2026-10-02T19:10:16.511Z" }
],
"next_cursor": null
}Errors
| HTTP status | code | Description |
|---|---|---|
| 400 | invalid_argument | limit isn't between 1 and 500, known_version isn't a non-negative integer, or cursor is invalid |
| 404 | not_found | The user doesn't exist or was deleted |
Block a user
Add {target} to {username}'s block list, with the effects described at the top of this page. If they're already blocked you still get 200 OK with changed false.
/{org_name}/{app_name}/users/{username}/blacklist/{target}Path parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
username | String | The block list's owner |
target | String | The user to block, not {username} |
Request example
curl -X PUT "$IM_API/$ORG/$APP/users/frank/blacklist/alice" \
-H "Authorization: Bearer $APP_TOKEN"Response
On success you get 200 OK:
| Field | Type | Description |
|---|---|---|
entry | Object | The block list entry. If they were already blocked, the original entry with its created_at unchanged |
changed | Boolean | Whether this request changed the block list |
blacklist_version | Number | The block list version: the new version when changed is true, the current one when false |
{
"entry": {
"username": "alice",
"nickname": "爱丽丝",
"avatar_url": "",
"created_at": "2026-10-02T19:09:27.367Z"
},
"changed": true,
"blacklist_version": 1
}Errors
| HTTP status | code | Description |
|---|---|---|
| 400 | invalid_argument | {target} is {username} |
| 404 | not_found | {username} or {target} doesn't exist or was deleted |
| 409 | limit_exceeded | The block list already has 1000 users; details.reason is blacklist_limit |
Unblock a user
Remove {target} from {username}'s block list. If they weren't blocked you still get 200 OK with changed false.
/{org_name}/{app_name}/users/{username}/blacklist/{target}Path parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
username | String | The block list's owner |
target | String | The user to unblock |
Request example
curl -X DELETE "$IM_API/$ORG/$APP/users/bob/blacklist/dave" \
-H "Authorization: Bearer $APP_TOKEN"Response
On success you get 200 OK:
| Field | Type | Description |
|---|---|---|
changed | Boolean | Whether this request changed the block list |
blacklist_version | Number | The block list version |
{
"changed": true,
"blacklist_version": 2
}Errors
| HTTP status | code | Description |
|---|---|---|
| 400 | invalid_argument | {target} is {username} |
| 404 | not_found | {username} or {target} doesn't exist or was deleted |
Block in batches
Block up to 100 users for one user at once, each under the same rules as Block a user; users already blocked count as success. Items are handled independently, see Batch APIs. Counts toward the app's quota once per item.
/{org_name}/{app_name}/users/{username}/blacklist/batchPath parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
username | String | The block list's owner |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
usernames | Array<String> | Yes | Users to block, 1 to 100 |
Request example
curl -X POST "$IM_API/$ORG/$APP/users/bob/blacklist/batch" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"usernames": ["dave", "erin", "nobody", "bob"]
}'Response
On success you get 200 OK. Repeated usernames aren't deduplicated; each occurrence is processed.
| Field | Type | Description |
|---|---|---|
added | Array<String> | Usernames blocked, including ones already blocked |
failed | Array<Object> | Items that failed, each with username (lowercase), code, message and optional details; errors as in Block a user |
{
"added": ["dave", "erin"],
"failed": [
{ "username": "nobody", "code": "not_found", "message": "用户不存在" },
{ "username": "bob", "code": "invalid_argument", "message": "不能把自己加入黑名单" }
]
}Batch APIs don't return changed or versions.
Errors
| HTTP status | code | Description |
|---|---|---|
| 400 | invalid_argument | usernames is empty or has more than 100 entries |
| 404 | not_found | {username} doesn't exist or was deleted |
Unblock in batches
Unblock up to 100 users for one user at once, each under the same rules as Unblock a user; users who weren't blocked count as success. Counts toward the app's quota once per item.
/{org_name}/{app_name}/users/{username}/blacklist/batch-deletePath parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
username | String | The block list's owner |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
usernames | Array<String> | Yes | Users to unblock, 1 to 100 |
Request example
curl -X POST "$IM_API/$ORG/$APP/users/bob/blacklist/batch-delete" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"usernames": ["dave", "carol", "nobody"]
}'Response
On success you get 200 OK:
| Field | Type | Description |
|---|---|---|
removed | Array<String> | Usernames unblocked, including ones who weren't blocked |
failed | Array<Object> | Items that failed, in the same format as Block in batches |
{
"removed": ["dave", "carol"],
"failed": [
{ "username": "nobody", "code": "not_found", "message": "用户不存在" }
]
}Errors
| HTTP status | code | Description |
|---|---|---|
| 400 | invalid_argument | usernames is empty or has more than 100 entries |
| 404 | not_found | {username} doesn't exist or was deleted |
Data structures
Block list entry
| Field | Type | Description |
|---|---|---|
username | String | The blocked username |
nickname | String | The blocked user's nickname; empty string if not set |
avatar_url | String | The blocked user's avatar address; empty string if not set |
created_at | String | When they were blocked |
{
"username": "alice",
"nickname": "爱丽丝",
"avatar_url": "",
"created_at": "2026-10-02T19:09:27.367Z"
}