好友
好友关系是双向的:A 是 B 的好友,B 也一定是 A 的好友。建立好友关系有两种方式:
- 用户在客户端发送好友申请,按对方的加好友方式处理,应用开启了加好友前回调时先由你的服务端决定是否允许,见好友申请;
- 业务服务端调用本页的接口直接添加:不经过申请,不检查双方的加好友方式和黑名单,也不调用加好友前回调,双方立即成为好友。适合业务中已经确立的关系(如同一个团队的同事),以及从其他 IM 导入好友。
本页接口路径中的 {username} 是关系的所有者,{friend} 是对方。备注和自定义属性只属于所有者这一侧,对方看不到;添加好友时可以分别为双方设置。
- 好友数上限:每个用户的好友数不能超过应用运行策略中的
friend_limit(默认 3000,可设为 1 到 100000,见运行策略)。成为好友时双方都要检查,任何一方已满都不能添加;调低上限不会删除已有的好友。 - 通知客户端:好友列表发生变化时,所有者的全部在线设备会实时收到变更通知(添加时为
friend.added,修改备注或自定义属性时为friend.updated,删除时为friend.removed)。添加和删除好友会同时改变双方的列表,双方都会收到。 - 单聊好友校验:应用在运行策略中开启
friend_check_enabled后,用户在客户端只能给好友发送单聊消息,给非好友发送时返回403 not_friend。 - 用户状态:用户被封禁不影响他的好友关系。用户被删除后,他的好友关系自动解除,他的好友会收到删除通知。
好友列表的版本号
每个用户的好友列表有一个版本号,列表内容每变化一次加 1。添加、修改、删除单个好友的接口都返回 changed 和 friend_version:changed 为 true 表示这次请求改变了所有者的好友列表,friend_version 是改变后的版本号;为 false 表示没有改变(如重复添加且内容相同、删除本来就不存在的好友),friend_version 是当前的版本号。因此重复调用这些接口都返回 200 OK,可以放心重试。
应用只读时
应用处于只读状态(如欠费只读,见限流与应用状态)时,添加好友和修改备注、自定义属性返回 403 app_unavailable;查询、删除好友不受影响。
查询好友列表
分页返回用户的好友列表,每页默认 100 个、最多 500 个。列表按固定的顺序返回(不按备注或昵称排序),展示时请自行排序。
/{org_name}/{app_name}/users/{username}/friends路径参数
org_name、app_name 见接入概述。
| 参数 | 类型 | 说明 |
|---|---|---|
username | String | 用户名,不区分大小写 |
查询参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
limit | Number | 否 | 每页条数,默认 100,取值 1 到 500 |
cursor | String | 否 | 下一页的游标,第一页不传,见分页 |
known_version | Number | 否 | 你保存的好友列表版本号,非负整数,只在请求第一页时生效。与当前版本号相同时只返回列表头(not_modified 为 true),不返回 items 和 next_cursor |
请求示例
curl "$IM_API/$ORG/$APP/users/alice/friends?limit=100" \
-H "Authorization: Bearer $APP_TOKEN"响应
成功返回 200 OK:
| 字段 | 类型 | 说明 |
|---|---|---|
version | Number | 好友列表当前的版本号,从未有过好友的用户为 0 |
not_modified | Boolean | 是否与请求中的 known_version 相同。为 true 时响应只有 version、not_modified、count、max_count 四个字段 |
count | Number | 当前的好友数 |
max_count | Number | 好友数上限,即应用的 friend_limit |
items | Array<Object> | 本页的好友,每项为好友对象 |
next_cursor | String | 下一页的游标,为 null 时没有下一页 |
{
"version": 2,
"not_modified": false,
"count": 2,
"max_count": 3000,
"items": [
{
"username": "bob",
"nickname": "鲍勃",
"avatar_url": "",
"remark": "老鲍",
"attributes": { "group": "同事", "star": "1" },
"add_source": "import",
"created_at": "2026-10-02T19:07:08.944Z"
},
{
"username": "carol",
"nickname": "卡罗尔",
"avatar_url": "",
"remark": "",
"attributes": null,
"add_source": "",
"created_at": "2026-10-02T19:07:08.989Z"
}
],
"next_cursor": null
}带 known_version=2 且列表没有变化时:
{
"version": 2,
"not_modified": true,
"count": 2,
"max_count": 3000
}- 分页拉取过程中如果列表发生了变化,后面几页的
version会与第一页不同。需要一份准确的完整列表时,发现version变化后从第一页重新拉取。 - 已被删除、但关系还在清理中的好友不会出现在列表中,这段时间里一页的条数可能少于
limit,count也可能暂时比实际返回的人数多。是否还有下一页只看next_cursor。
错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 400 | invalid_argument | limit 不在 1 到 500 之间、known_version 不是非负整数,或 cursor 无效 |
| 404 | not_found | 用户不存在或已删除 |
检查好友关系
批量检查一个用户与其他用户的关系:是否好友、是否拉黑了对方、两人之间是否有待处理的好友申请。常用于在业务页面上显示“加好友”“等待验证”等状态。
/{org_name}/{app_name}/users/{username}/friends/check路径参数
org_name、app_name 见接入概述。
| 参数 | 类型 | 说明 |
|---|---|---|
username | String | 用户名 |
请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
usernames | Array<String> | 是 | 要检查的用户名,1 到 100 个 |
请求示例
curl -X POST "$IM_API/$ORG/$APP/users/alice/friends/check" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"usernames": ["bob", "erin", "frank", "Carol", "alice", "nobody"]
}'响应
成功返回 200 OK,items 按请求中的顺序排列,用户名转为小写后去重;不存在或已删除的用户、{username} 本人不出现在结果中。每一项为:
| 字段 | 类型 | 说明 |
|---|---|---|
username | String | 对方的用户名 |
is_friend | Boolean | 是否好友 |
blocked | Boolean | {username} 是否把对方加入了黑名单。不返回对方是否拉黑了 {username} |
request | String | 两人之间未过期的待处理好友申请:sent 为 {username} 发出、对方尚未处理;received 为对方发来、{username} 尚未处理;没有时为 null |
{
"items": [
{ "username": "bob", "is_friend": true, "blocked": false, "request": null },
{ "username": "erin", "is_friend": false, "blocked": false, "request": "received" },
{ "username": "frank", "is_friend": false, "blocked": false, "request": "sent" },
{ "username": "carol", "is_friend": true, "blocked": false, "request": null }
]
}这个接口是读操作,无论检查多少个用户都只计一次调用。
错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 400 | invalid_argument | usernames 为空或超过 100 个 |
| 404 | not_found | {username} 不存在或已删除 |
查询单个好友
/{org_name}/{app_name}/users/{username}/friends/{friend}路径参数
org_name、app_name 见接入概述。
| 参数 | 类型 | 说明 |
|---|---|---|
username | String | 关系的所有者 |
friend | String | 好友的用户名 |
请求示例
curl "$IM_API/$ORG/$APP/users/alice/friends/bob" \
-H "Authorization: Bearer $APP_TOKEN"响应
成功返回 200 OK,响应体为好友对象。
{
"username": "bob",
"nickname": "鲍勃",
"avatar_url": "",
"remark": "老鲍",
"attributes": { "group": "同事", "star": "1" },
"add_source": "import",
"created_at": "2026-10-02T19:07:08.944Z"
}错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 400 | invalid_argument | {friend} 与 {username} 是同一个用户 |
| 404 | not_found | 用户不存在或已删除(message 为“用户不存在”),或两人不是好友(message 为“对方不是你的好友”) |
添加好友
直接让两个用户成为好友,不经过申请,不检查双方的加好友方式和黑名单,只检查双方的好友数上限。
- 双方同时成为好友:
remark、attributes只设置{username}这一侧,add_source双方相同。对方一侧的备注取对方之前发给{username}的待处理申请中预设的备注,没有时为空。{username}一侧没有传remark时,同样取{username}发给对方的待处理申请中预设的备注。 - 处理两人之间的申请:两人之间未过期的待处理好友申请改为“已成为好友”(
accepted)。 - 已经是好友时视为成功:把这次传入的
remark、attributes写入{username}一侧(没传的项保持不变),add_source和created_at不变。内容有变化时changed为true,否则为false。导入时可以先后为双方各调用一次,各自的备注都能写进去。 - 双方的在线设备都会收到新好友的通知;已经是好友而只修改了备注或自定义属性时,只有
{username}的在线设备收到修改的通知。
/{org_name}/{app_name}/users/{username}/friends/{friend}路径参数
org_name、app_name 见接入概述。
| 参数 | 类型 | 说明 |
|---|---|---|
username | String | 关系的所有者 |
friend | String | 要添加的好友的用户名,不能是 {username} 本人 |
请求体
请求体可以省略。不能包含 username 字段,对方取自路径。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
remark | String | 否 | {username} 给对方的备注,最长 64 个字符,不能包含控制字符,首尾空白自动去掉 |
attributes | Object | 否 | {username} 给对方设置的自定义属性,字符串键值对,规则见好友对象。已经是好友时按项合并,与修改好友相同 |
add_source | String | 否 | 添加来源,如 search、qrcode、group:1839201838123,最长 32 个字符,由字母、数字和 _、-、.、: 组成。双方相同,成为好友后不能修改 |
created_at | String | 否 | 成为好友的时间,RFC 3339 格式,不能晚于当前时间。用于从其他 IM 导入时保留原来的时间,默认为当前时间;已经是好友时忽略 |
请求示例
curl -X PUT "$IM_API/$ORG/$APP/users/alice/friends/bob" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"remark": "老鲍",
"attributes": { "star": "1", "group": "同事" },
"add_source": "import"
}'响应
成功返回 200 OK:
| 字段 | 类型 | 说明 |
|---|---|---|
friend | Object | {username} 一侧的好友对象 |
changed | Boolean | 这次请求是否改变了 {username} 的好友列表 |
friend_version | Number | {username} 的好友列表版本号,见本页开头的说明 |
{
"friend": {
"username": "bob",
"nickname": "鲍勃",
"avatar_url": "",
"remark": "老鲍",
"attributes": { "group": "同事", "star": "1" },
"add_source": "import",
"created_at": "2026-10-02T19:07:08.944Z"
},
"changed": true,
"friend_version": 1
}错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 400 | invalid_argument | {friend} 是 {username} 本人;请求体包含 username;remark、attributes、add_source 不符合规则;created_at 晚于当前时间 |
| 404 | not_found | {username} 或 {friend} 不存在或已删除 |
| 409 | limit_exceeded | 好友数已达上限。details.reason 为 friend_limit 时是 {username} 的好友数已满,为 peer_friend_limit 时是对方的好友数已满 |
{
"error": {
"code": "limit_exceeded",
"message": "对方的好友数已达上限",
"details": { "reason": "peer_friend_limit" },
"request_id": "QHDK7PQXPV3LFKEFLF37DST5RR"
}
}批量添加好友
为一个用户一次添加最多 100 位好友,每一项的规则与添加好友相同。各项分别处理、互不影响,见批量接口。按项数计入应用的调用额度。
/{org_name}/{app_name}/users/{username}/friends/batch路径参数
org_name、app_name 见接入概述。
| 参数 | 类型 | 说明 |
|---|---|---|
username | String | 关系的所有者 |
请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
friends | Array<Object> | 是 | 要添加的好友,1 到 100 项 |
friends[].username | String | 是 | 好友的用户名 |
friends[].remark | String | 否 | 同添加好友 |
friends[].attributes | Object | 否 | 同添加好友 |
friends[].add_source | String | 否 | 同添加好友 |
friends[].created_at | String | 否 | 同添加好友 |
请求示例
curl -X POST "$IM_API/$ORG/$APP/users/carol/friends/batch" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"friends": [
{ "username": "dave", "remark": "戴夫", "add_source": "import", "created_at": "2025-03-01T10:00:00Z" },
{ "username": "erin", "attributes": { "group": "同学" } },
{ "username": "alice" },
{ "username": "nobody" }
]
}'响应
成功返回 200 OK。同一个用户名出现多次时不去重,按出现的次数逐个处理。
| 字段 | 类型 | 说明 |
|---|---|---|
added | Array<Object> | 添加成功的项,每项为 {username} 一侧的好友对象,包括原本就是好友的 |
failed | Array<Object> | 失败的项,每项为 username(小写)、code、message 和可选的 details,错误与添加好友相同 |
{
"added": [
{
"username": "dave",
"nickname": "戴夫",
"avatar_url": "",
"remark": "戴夫",
"attributes": null,
"add_source": "import",
"created_at": "2025-03-01T10:00:00.000Z"
},
{
"username": "erin",
"nickname": "艾琳",
"avatar_url": "",
"remark": "",
"attributes": { "group": "同学" },
"add_source": "",
"created_at": "2026-10-02T19:10:22.454Z"
},
{
"username": "alice",
"nickname": "爱丽丝",
"avatar_url": "",
"remark": "",
"attributes": null,
"add_source": "",
"created_at": "2026-10-02T19:07:08.989Z"
}
],
"failed": [
{ "username": "nobody", "code": "not_found", "message": "用户不存在" }
]
}批量接口不返回 changed 和版本号。
错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 400 | invalid_argument | friends 为空或超过 100 项 |
| 404 | not_found | {username} 不存在或已删除 |
修改好友备注和自定义属性
修改 {username} 给好友设置的备注和自定义属性,只影响 {username} 这一侧。remark 和 attributes 至少传一项,没有传的保持不变。内容有变化时 {username} 的在线设备会收到修改的通知;与原值相同时 changed 为 false。
/{org_name}/{app_name}/users/{username}/friends/{friend}路径参数
org_name、app_name 见接入概述。
| 参数 | 类型 | 说明 |
|---|---|---|
username | String | 关系的所有者 |
friend | String | 好友的用户名 |
请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
remark | String | 否 | 备注,最长 64 个字符,不能包含控制字符,首尾空白自动去掉;传空字符串表示清除 |
attributes | Object | 否 | 要修改的自定义属性:只传需要修改的项,值为 null 表示删除这一项;整个字段传 null 表示清空全部。合并后的结果须符合好友对象中的规则 |
请求示例
把备注改为“鲍总”,删除 star,新增 tag:
curl -X PATCH "$IM_API/$ORG/$APP/users/alice/friends/bob" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"remark": "鲍总",
"attributes": { "star": null, "tag": "vip" }
}'响应
成功返回 200 OK,字段与添加好友的响应相同。
{
"friend": {
"username": "bob",
"nickname": "鲍勃",
"avatar_url": "",
"remark": "鲍总",
"attributes": { "group": "同事", "tag": "vip" },
"add_source": "import",
"created_at": "2026-10-02T19:07:08.944Z"
},
"changed": true,
"friend_version": 3
}错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 400 | invalid_argument | remark 和 attributes 都没有传;remark 或 attributes 不符合规则;{friend} 是 {username} 本人 |
| 404 | not_found | 用户不存在或已删除,或两人不是好友 |
删除好友
解除两个用户的好友关系,双方同时解除,两边的备注和自定义属性一并删除。双方的在线设备都会收到删除的通知,原因是“服务端删除”,不会让一方误以为是对方删除了自己。删除好友不影响黑名单,也不影响两人已有的会话和历史消息。
两人本来就不是好友时同样返回 200 OK,changed 为 false。
/{org_name}/{app_name}/users/{username}/friends/{friend}路径参数
org_name、app_name 见接入概述。
| 参数 | 类型 | 说明 |
|---|---|---|
username | String | 关系的所有者 |
friend | String | 好友的用户名 |
请求示例
curl -X DELETE "$IM_API/$ORG/$APP/users/carol/friends/erin" \
-H "Authorization: Bearer $APP_TOKEN"响应
成功返回 200 OK:
| 字段 | 类型 | 说明 |
|---|---|---|
changed | Boolean | 是否确实删除了好友关系 |
friend_version | Number | {username} 的好友列表版本号 |
{
"changed": true,
"friend_version": 4
}错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 400 | invalid_argument | {friend} 是 {username} 本人 |
| 404 | not_found | {username} 或 {friend} 不存在或已删除 |
批量删除好友
为一个用户一次删除最多 100 位好友,每一项的规则与删除好友相同,本来就不是好友的也算删除成功。按项数计入应用的调用额度。
/{org_name}/{app_name}/users/{username}/friends/batch-delete路径参数
org_name、app_name 见接入概述。
| 参数 | 类型 | 说明 |
|---|---|---|
username | String | 关系的所有者 |
请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
usernames | Array<String> | 是 | 要删除的好友的用户名,1 到 100 个 |
请求示例
curl -X POST "$IM_API/$ORG/$APP/users/carol/friends/batch-delete" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"usernames": ["dave", "bob", "nobody"]
}'响应
成功返回 200 OK:
| 字段 | 类型 | 说明 |
|---|---|---|
deleted | Array<String> | 删除成功的用户名,包括本来就不是好友的 |
failed | Array<Object> | 失败的项,每项为 username(小写)、code、message 和可选的 details,错误与删除好友相同 |
{
"deleted": ["dave", "bob"],
"failed": [
{ "username": "nobody", "code": "not_found", "message": "用户不存在" }
]
}错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 400 | invalid_argument | usernames 为空或超过 100 个 |
| 404 | not_found | {username} 不存在或已删除 |
删除全部好友
删除一个用户的全部好友,用于员工离职时清空关系、回滚一次错误的导入等场景。每次调用最多删除 100 位,每位好友的规则与删除好友相同。响应中 has_more 为 true 时请再次调用,直到为 false。
每次调用按这次取出的好友人数计入应用的调用额度(没有好友时只计一次)。中途出错时返回错误,已经删除的不会恢复,再次调用即可继续。
/{org_name}/{app_name}/users/{username}/friends路径参数
org_name、app_name 见接入概述。
| 参数 | 类型 | 说明 |
|---|---|---|
username | String | 用户名 |
请求示例
curl -X DELETE "$IM_API/$ORG/$APP/users/alice/friends" \
-H "Authorization: Bearer $APP_TOKEN"响应
成功返回 200 OK:
| 字段 | 类型 | 说明 |
|---|---|---|
deleted_count | Number | 这次删除的好友人数 |
has_more | Boolean | 是否还有没删除的好友 |
{
"deleted_count": 5,
"has_more": false
}错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 404 | not_found | 用户不存在或已删除 |
数据结构
好友对象
所有者视角的一位好友。
| 字段 | 类型 | 说明 |
|---|---|---|
username | String | 好友的用户名 |
nickname | String | 好友的昵称,没有设置时为空字符串 |
avatar_url | String | 好友的头像地址,没有设置时为空字符串 |
remark | String | 所有者给好友设置的备注,没有时为空字符串 |
attributes | Object | 所有者给好友设置的自定义属性,字符串键值对,没有时为 null |
add_source | String | 添加来源,没有时为空字符串 |
created_at | String | 成为好友的时间 |
{
"username": "bob",
"nickname": "鲍勃",
"avatar_url": "",
"remark": "老鲍",
"attributes": { "group": "同事", "star": "1" },
"add_source": "import",
"created_at": "2026-10-02T19:07:08.944Z"
}nickname、avatar_url取自好友当前的用户资料。好友修改资料后,不会通知他的好友。- 备注:最长 64 个字符,不能包含控制字符。
- 自定义属性:最多 16 项,JSON 编码后合计不超过 1 KB;键为 1 到 32 个字符,由字母、数字和
_、-、.组成;值为字符串。可以用它实现星标好友、好友分组等功能。 - 添加来源:记录两人是怎样认识的,取值由你定义,如
search(搜索)、qrcode(扫码)、group:1839201838123(在某个群里)。由用户在客户端发送申请时提交的来源未经核实,只能用于展示和统计,不要作为权限依据。成为好友后不能修改。
