用户管理
用户是你的 App 中使用即时通讯的终端用户,属于一个应用,不同应用的用户完全隔离。推荐的做法是:用户在你的业务系统注册时,业务服务端调用创建用户建立对应的 IM 用户;也可以在签发登录凭证时让服务端自动创建,省去单独建号的步骤。
本页介绍用户的创建、查询、修改资料和删除。设置密码、封禁和解封见密码与封禁,登录和登录设备见登录与登录设备。
用户名与资料
| 项 | 规则 |
|---|---|
用户名 username | 1 到 64 个字符,由字母、数字、_、-、. 组成,不能是 . 或 ..。不区分大小写:大写字母自动转为小写,Tom 和 tom 是同一个用户,响应中的用户名一律为小写。创建后不能修改 |
密码 password | 可选,1 到 64 个字符,不限制复杂度,原样保存(不去除首尾空格)。没有密码的用户只能用登录凭证登录 |
昵称 nickname | 最长 64 个字符,不能包含控制字符,首尾空白自动去除,可以为空 |
头像 avatar_url | http 或 https 地址,最长 512 个字符,不能包含空白,可以为空。可以是本服务的头像地址,也可以是你自己的地址,见头像。服务端不会访问它 |
自定义属性 attributes | 字符串键值对,用于存放性别、签名等你自定义的资料。键 1 到 32 个字符,由字母、数字、_、-、. 组成,区分大小写;值为任意文本;最多 32 项,按 JSON 编码后合计不超过 4 KB(4096 字节) |
所有接口都用用户名表示用户,路径中的用户名同样不区分大小写。
用户名的选择
建议直接使用业务系统中的用户 ID 作为用户名。不要使用手机号、邮箱等个人信息:用户名会展示给同一应用的其他用户,客户端也能据此判断某个用户名是否已注册。
资料对所有用户可见
昵称、头像和自定义属性对同一应用的所有用户可见(客户端可以查询任意用户的资料用于展示),不要在其中存放手机号、证件号等敏感信息。
内容安全:创建用户和修改资料时,昵称和头像要经过内容安全检查(你的服务端提交的默认只按平台规则检查,见服务端提交的内容)。修改资料时只检查与原值不同的字段,清空字段和自定义属性不检查:
- 不通过时不写入,返回
403 content_rejected,details.field为nickname或avatar_url,见调用方看到的错误; - 昵称命中替换规则的,写入替换后的内容(命中的文字替换为
*),以响应中的用户对象为准; - 应用开启了头像审核时,头像地址必须是可以公开访问的
http、https地址,内网地址、无法解析的域名同样被拒绝; - 之后被判定违规的昵称和头像可能被清除,清除后与修改资料一样通知相关的客户端,见发出之后的处置。
应用中未删除的用户数(含已封禁的用户)不能超过应用套餐的注册用户数额度,见套餐与账单。
头像
用户头像可以存放在本服务,也可以使用你自己的图片地址:
- 使用本服务的头像:以用途
user_avatar上传图片,用owner指定使用这个头像的用户(必须是已存在的用户),完成上传后得到头像的公开地址(文件对象的url),如https://cdn.example.com/t99604914749046784/a99604957400924160/u/99606512787259392_i13hkkg3.jpg,再修改用户资料把它填进avatar_url。图片会被缩放到长边不超过 640 像素,公开地址任何人都可以直接访问。导入带头像的用户时,先创建用户,再上传头像,最后修改资料。 - 头像文件的保留:服务按用户资料中当前的
avatar_url判断头像是否在使用。上传后 24 小时内没有设为头像的,以及被替换(改为其他地址或清空)7 天后的头像文件会被删除,之后原来的地址无法访问。一个user_avatar文件只能作为它的owner的头像,填进其他用户的资料不算在使用,owner换头像 7 天后这个地址同样失效。 - 使用你自己的地址:服务端接口写入的
avatar_url只检查格式,可以是任意主机的地址,这样的头像不经过本服务。用户在客户端修改本人头像时,如果应用在运行策略中开启了media_url_only,只能使用本应用的头像地址或media_allowed_hosts中主机的https地址,否则返回400 invalid_argument,details.reason为url_not_allowed。
创建用户
创建一个用户。用户名已被占用时返回 409 already_exists;请求超时后重试时,收到 already_exists 可以视为上次已经创建成功。
/{org_name}/{app_name}/users路径参数
org_name、app_name 见接入概述。
请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
username | String | 是 | 用户名,规则见用户名与资料 |
password | String | 否 | 密码,1 到 64 个字符。省略或为空字符串表示不设密码 |
nickname | String | 否 | 昵称,最长 64 个字符 |
avatar_url | String | 否 | 头像地址,http 或 https 地址,最长 512 个字符 |
attributes | Object | 否 | 自定义属性,键和值都是字符串,最多 32 项 |
请求示例
curl -X POST "$IM_API/$ORG/$APP/users" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"username": "zhangsan",
"password": "Passw0rd!",
"nickname": "张三",
"avatar_url": "https://cdn.example.com/avatar/zhangsan.png",
"attributes": { "gender": "1", "sign": "你好" }
}'响应
成功返回 201 Created,响应体为用户对象。
{
"username": "zhangsan",
"nickname": "张三",
"avatar_url": "https://cdn.example.com/avatar/zhangsan.png",
"attributes": { "gender": "1", "sign": "你好" },
"status": "active",
"status_reason": null,
"disabled_by": null,
"disabled_until": null,
"has_password": true,
"created_via": "openapi",
"created_at": "2026-10-02T19:05:46.167Z",
"last_login_at": null,
"version": 1
}错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 400 | invalid_argument | 参数不符合用户名与资料中的规则,message 说明了具体原因 |
| 403 | app_unavailable | 应用处于只读状态,不能创建用户,见限流与应用状态 |
| 403 | content_rejected | 昵称或头像未通过内容安全检查,details.field 为 nickname 或 avatar_url,details.reason 说明原因 |
| 409 | already_exists | 用户名已被占用 |
| 409 | limit_exceeded | 应用的注册用户数已达上限 |
| 429 | rate_limited | 带密码创建时超出了应用计算密码哈希的额度(每个应用每秒 100 次,与设置密码共用),按 Retry-After 稍后重试 |
批量创建用户
一次创建 1 到 100 个用户,按顺序逐个创建,某个用户失败不影响其他用户。适合从其他系统导入用户,响应格式见批量接口。
整个请求按用户数计入应用的 OpenAPI 调用额度(每秒请求数):100 个用户的请求计为 100 次,额度不足时整个请求返回 429 rate_limited。带密码的用户还计入应用计算密码哈希的额度(每秒 100 次),超出额度的用户出现在 failed 中,错误码为 rate_limited,可以稍后单独重试这些用户。
批量创建时,内容安全只按词库检查昵称,需要第三方审核的昵称和头像改为创建之后再审核,违规的从资料中清除。被拒绝的用户出现在 failed 中,错误码为 content_rejected。
/{org_name}/{app_name}/users/batch请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
users | Array<Object> | 是 | 要创建的用户,1 到 100 个,每项的字段与创建用户的请求体相同 |
请求示例
curl -X POST "$IM_API/$ORG/$APP/users/batch" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"users": [
{ "username": "wangwu", "nickname": "王五" },
{ "username": "zhaoliu", "password": "123456" },
{ "username": "ZhangSan" },
{ "username": "bad name" }
]
}'响应
成功返回 200 OK。即使全部用户都创建失败,也返回 200,请检查 failed。
| 字段 | 类型 | 说明 |
|---|---|---|
created | Array<Object> | 创建成功的用户,每项为用户对象,按请求中的顺序 |
failed | Array<Object> | 创建失败的用户,按请求中的顺序 |
failed[].username | String | 请求中的用户名(转为小写) |
failed[].code | String | 错误码,与创建用户的错误码相同,如 already_exists、invalid_argument、content_rejected、limit_exceeded、rate_limited |
failed[].message | String | 错误说明 |
{
"created": [
{
"username": "wangwu",
"nickname": "王五",
"avatar_url": "",
"attributes": {},
"status": "active",
"status_reason": null,
"disabled_by": null,
"disabled_until": null,
"has_password": false,
"created_via": "openapi",
"created_at": "2026-10-02T19:06:04.505Z",
"last_login_at": null,
"version": 1
},
{
"username": "zhaoliu",
"nickname": "",
"avatar_url": "",
"attributes": {},
"status": "active",
"status_reason": null,
"disabled_by": null,
"disabled_until": null,
"has_password": true,
"created_via": "openapi",
"created_at": "2026-10-02T19:06:04.563Z",
"last_login_at": null,
"version": 1
}
],
"failed": [
{ "username": "zhangsan", "code": "already_exists", "message": "用户名已被占用" },
{ "username": "bad name", "code": "invalid_argument", "message": "用户名应为 1 到 64 位,由字母、数字、_、-、. 组成,且不能是 . 或 .." }
]
}错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 400 | invalid_argument | users 为空或超过 100 个 |
| 403 | app_unavailable | 应用处于只读状态,不能创建用户 |
| 429 | rate_limited | 应用的 OpenAPI 调用额度不足以处理这么多用户,整个请求没有执行 |
查询用户列表
分页列出应用中的用户,不含已删除的用户。默认按创建顺序排列;带 username_prefix 时按用户名排序。分页方式见分页,换了筛选条件后请从第一页开始查询。
/{org_name}/{app_name}/users查询参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
status | String | 否 | 按状态筛选:active 正常,disabled 已封禁。省略时两者都列出 |
username_prefix | String | 否 | 按用户名前缀搜索,1 到 64 个用户名字符,不区分大小写,按字面匹配(_ 不是通配符) |
limit | Number | 否 | 每页数量,1 到 100,默认 20 |
cursor | String | 否 | 分页游标,取上一页响应中的 next_cursor;省略时从第一页开始 |
请求示例
curl "$IM_API/$ORG/$APP/users?status=active&limit=2" \
-H "Authorization: Bearer $APP_TOKEN"响应
成功返回 200 OK:
| 字段 | 类型 | 说明 |
|---|---|---|
items | Array<Object> | 本页的用户,每项为用户对象 |
next_cursor | String | 下一页的游标,可为 null(没有下一页) |
{
"items": [
{
"username": "zhangsan",
"nickname": "张三",
"avatar_url": "https://cdn.example.com/avatar/zhangsan.png",
"attributes": { "gender": "1", "sign": "你好" },
"status": "active",
"status_reason": null,
"disabled_by": null,
"disabled_until": null,
"has_password": true,
"created_via": "openapi",
"created_at": "2026-10-02T19:05:46.167Z",
"last_login_at": null,
"version": 1
},
{
"username": "lisi",
"nickname": "",
"avatar_url": "",
"attributes": {},
"status": "active",
"status_reason": null,
"disabled_by": null,
"disabled_until": null,
"has_password": false,
"created_via": "openapi",
"created_at": "2026-10-02T19:05:46.203Z",
"last_login_at": null,
"version": 1
}
],
"next_cursor": "Rq65HvagQGJhPXM4qOLjuRBLiQjV-J2USEzW9r0fve4kz850Z89l..."
}错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 400 | invalid_argument | status 不是 active 或 disabled;username_prefix 包含用户名以外的字符或超过 64 个字符;limit 超出范围;游标无效或不属于这种查询 |
按用户名批量查询
一次查询 1 到 100 个用户。结果按请求中的顺序排列;不存在或已删除的用户不出现在结果中,重复的和格式不对的用户名会被忽略。
/{org_name}/{app_name}/users/lookup请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
usernames | Array<String> | 是 | 要查询的用户名,1 到 100 个,不区分大小写 |
请求示例
curl -X POST "$IM_API/$ORG/$APP/users/lookup" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"usernames": ["LISI", "nobody", "zhangsan", "lisi"]
}'响应
成功返回 200 OK。items 为找到的用户,每项为用户对象。示例中 nobody 不存在,重复的 lisi 只返回一次。
{
"items": [
{
"username": "lisi",
"nickname": "",
"avatar_url": "",
"attributes": {},
"status": "active",
"status_reason": null,
"disabled_by": null,
"disabled_until": null,
"has_password": false,
"created_via": "openapi",
"created_at": "2026-10-02T19:05:46.203Z",
"last_login_at": null,
"version": 1
},
{
"username": "zhangsan",
"nickname": "张三",
"avatar_url": "https://cdn.example.com/avatar/zhangsan.png",
"attributes": { "gender": "1", "sign": "你好" },
"status": "active",
"status_reason": null,
"disabled_by": null,
"disabled_until": null,
"has_password": true,
"created_via": "openapi",
"created_at": "2026-10-02T19:05:46.167Z",
"last_login_at": null,
"version": 1
}
]
}错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 400 | invalid_argument | usernames 为空或超过 100 个 |
查询用户
查询一个用户的详细信息,包括封禁状态。
/{org_name}/{app_name}/users/{username}路径参数
org_name、app_name 见接入概述。
| 参数 | 类型 | 说明 |
|---|---|---|
username | String | 用户名,不区分大小写 |
请求示例
curl "$IM_API/$ORG/$APP/users/zhangsan" \
-H "Authorization: Bearer $APP_TOKEN"响应
成功返回 200 OK,响应体为用户对象。
{
"username": "zhangsan",
"nickname": "张三",
"avatar_url": "https://cdn.example.com/avatar/zhangsan.png",
"attributes": { "gender": "1", "sign": "你好" },
"status": "active",
"status_reason": null,
"disabled_by": null,
"disabled_until": null,
"has_password": true,
"created_via": "openapi",
"created_at": "2026-10-02T19:05:46.167Z",
"last_login_at": null,
"version": 1
}错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 404 | not_found | 用户不存在或已删除。格式不对的用户名同样返回 not_found |
修改用户资料
修改用户的昵称、头像和自定义属性,只传需要修改的字段,至少传一个。修改后,该用户在线的设备会收到资料变更的通知。
自定义属性按项合并,不会整体替换:
attributes中出现的键,值为字符串时新增或覆盖该项,值为null时删除该项;- 没有出现的键保持不变;
attributes整体传null时清空全部自定义属性。
合并后的属性同样要满足最多 32 项、合计不超过 4 KB 的限制。两个请求同时修改不同的项时不会互相覆盖。昵称或头像传空字符串表示清空。
version 可选:不传时直接修改;传入时必须与用户当前的 version 一致,否则返回 409 version_conflict,见并发修改。提交的内容与当前资料相同时,不递增 version,也不发送通知。
/{org_name}/{app_name}/users/{username}路径参数
org_name、app_name 见接入概述。
| 参数 | 类型 | 说明 |
|---|---|---|
username | String | 用户名 |
请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
nickname | String | 否 | 新的昵称,空字符串表示清空 |
avatar_url | String | 否 | 新的头像地址,空字符串表示清空,规则见头像。替换或清空本服务的头像后,原来的头像文件在 7 天后删除 |
attributes | Object | 否 | 要修改的自定义属性,按上文的规则合并。值为 null 表示删除该项,整体为 null 表示清空 |
version | Number | 否 | 读取到的用户 version,传入时用于检查并发修改 |
请求示例
把昵称改为“张三丰”,删除属性 sign,新增属性 level,保留其他属性:
curl -X PATCH "$IM_API/$ORG/$APP/users/zhangsan" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"nickname": "张三丰",
"attributes": { "sign": null, "level": "vip" }
}'把头像改为以用途 user_avatar 上传后得到的公开地址:
curl -X PATCH "$IM_API/$ORG/$APP/users/zhangsan" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"avatar_url": "https://cdn.example.com/t99604914749046784/a99604957400924160/u/99606512787259392_i13hkkg3.jpg"
}'响应
成功返回 200 OK,响应体为修改后的用户对象。
{
"username": "zhangsan",
"nickname": "张三丰",
"avatar_url": "https://cdn.example.com/avatar/zhangsan.png",
"attributes": { "gender": "1", "level": "vip" },
"status": "active",
"status_reason": null,
"disabled_by": null,
"disabled_until": null,
"has_password": true,
"created_via": "openapi",
"created_at": "2026-10-02T19:05:46.167Z",
"last_login_at": null,
"version": 2
}错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 400 | invalid_argument | 没有传任何需要修改的字段;字段不符合用户名与资料中的规则;合并后的自定义属性超过 32 项或 4 KB |
| 403 | app_unavailable | 应用处于只读状态,不能修改资料 |
| 403 | content_rejected | 修改的昵称或头像未通过内容安全检查,details.field 为 nickname 或 avatar_url,details.reason 说明原因 |
| 404 | not_found | 用户不存在或已删除 |
| 409 | version_conflict | version 与用户当前的不一致,请重新查询后再修改 |
删除用户
删除一个用户。删除不可撤销,删除后:
- 该用户的所有设备立即下线,在线的设备会被断开连接并收到账号已被删除的通知;此前签发、尚未使用的登录凭证作废;
- 清空密码、昵称、头像、自定义属性和全局禁言,查询该用户返回
404 not_found,用户不再计入应用的用户数; - 用户名被释放,可以用同一个用户名重新创建用户。新用户与已删除的用户是两个不同的用户,不会继承旧用户的好友、群和会话;
- 好友:他的好友关系、好友申请和黑名单被清除,他的好友会收到好友已被删除的通知;
- 群组:他被移出加入的全部群,以他为对象的入群申请、邀请和群黑名单记录被删除。他是群主的,群主转给加入最早的管理员,没有管理员时转给加入最早的成员;群里没有其他成员时解散该群;
- 消息与会话:他发过的消息默认保留,发送者显示为已删除的用户;应用的运行策略开启了删除用户时擦除消息(
erase_messages_on_user_delete)的,他发过的消息会被擦除。他与其他用户的单聊会话在对方那里保留,对方可以查看历史消息,但不能再给他发消息; - 推送:他的推送设置、会话免打扰和登记的推送设备一并删除,见推送设备与设置;
- 内容安全:他的违规记录一并删除;
- 文件:所属用户(
owner)为他的文件中,用户头像被删除,头像的公开地址在约 10 分钟后无法访问(浏览器、CDN 中已缓存的图片最长 1 天后失效);开启了erase_messages_on_user_delete的,附件和群文件也被删除,其他人再下载时提示文件已过期;没有开启的,附件按保留期删除,群文件保留在群中。群头像不删除,由群继续使用。用户在客户端上传的文件,所属用户就是他本人。
好友、群组和文件的清理由后台异步完成,通常在 1 分钟左右完成;消息和会话在删除约 10 分钟后清理。
被平台封禁的用户不能删除,见密码与封禁。重试时收到 404 not_found 可以视为上次已经删除成功。
用户注销账号
客户端没有删除本人账号的接口。App 需要提供注销账号功能时,由 App 调用你的业务系统,业务系统验证用户身份后调用本接口删除 IM 用户。
/{org_name}/{app_name}/users/{username}路径参数
org_name、app_name 见接入概述。
| 参数 | 类型 | 说明 |
|---|---|---|
username | String | 用户名 |
请求示例
curl -X DELETE "$IM_API/$ORG/$APP/users/wangwu" \
-H "Authorization: Bearer $APP_TOKEN"响应
成功返回 204 No Content,没有响应体。
错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 403 | permission_denied | 该用户被平台封禁,不能删除 |
| 404 | not_found | 用户不存在或已删除 |
数据结构
用户对象
| 字段 | 类型 | 说明 |
|---|---|---|
username | String | 用户名,小写 |
nickname | String | 昵称,没有时为空字符串 |
avatar_url | String | 头像地址,没有时为空字符串 |
attributes | Object | 自定义属性,键和值都是字符串,没有时为 {} |
status | String | 用户状态:active 正常,disabled 已封禁 |
status_reason | String | 封禁原因,可为 null(没有封禁,或封禁时没有填写原因) |
disabled_by | String | 封禁方:tenant 由你的业务服务端或控制台封禁,platform 由平台封禁。没有封禁时为 null |
disabled_until | String | 封禁的到期时间,到期后自动解封。没有封禁或永久封禁时为 null |
has_password | Boolean | 是否设置了密码 |
created_via | String | 创建方式:openapi 由 OpenAPI 创建(包括签发登录凭证时自动创建),console 在控制台创建,client 客户端自注册 |
created_at | String | 创建时间 |
last_login_at | String | 最近一次登录的时间,可为 null(从未登录) |
version | Number | 版本号。资料、密码或封禁状态变化时递增,修改资料时可用于检查并发修改 |
时间格式见数据格式。
{
"username": "lisi",
"nickname": "李四",
"avatar_url": "",
"attributes": { "gender": "2" },
"status": "disabled",
"status_reason": "发布违规内容",
"disabled_by": "tenant",
"disabled_until": "2026-10-03T19:08:44.477Z",
"has_password": true,
"created_via": "openapi",
"created_at": "2026-10-02T19:05:46.203Z",
"last_login_at": "2026-10-02T19:08:44.402Z",
"version": 5
}