聊天室消息
聊天室消息只推给此刻在聊天室里的连接:不保存离线消息,不计未读数,不发离线推送,也不进入用户的会话和消息导出。你的业务服务端可以向聊天室发送系统通知、主播公告、礼物结算等消息,查询聊天室最近的消息,撤回违规的消息。
消息的优先级,以及消息过多时的合并、限速和丢弃规则见聊天室管理。
与单聊、群聊消息的区别
| 单聊、群聊消息 | 聊天室消息 | |
|---|---|---|
| 接收者 | 会话的成员,离线的设备上线后补齐 | 此刻在聊天室里的连接,离线期间的消息收不到 |
| 保存 | 保存在会话中,可以查询历史消息 | 只保存最近的消息(默认最近 50 条,最多 24 小时),低优先级的消息不保存 |
| 消息类型 | 见消息类型 | text、image、voice、video、file、location、custom,body 和 ext 的格式与单聊、群聊消息相同;不支持 tip 等系统专用的类型 |
| 大小上限 | 运行策略 max_message_body_bytes,默认 5 KB | 运行策略 max_chatroom_message_bytes,默认 2 KB,可设 256 字节到 8 KB |
| 优先级 | 没有 | high、normal、low,消息过多时按优先级限流和丢弃 |
| 发送者的资料 | 消息中只有发送者的用户名 | 消息中带发送时的昵称、头像和在聊天室中的身份,接收方不必逐个查询 |
| 其他功能 | @、引用回复、已读回执、编辑、置顶、回应、离线推送 | 都不支持,消息发出后只能撤回 |
| 防止重复发送 | 用 client_msg_id 防止重复写入 | 同一发送者 5 分钟内相同的 client_msg_id 只发送一次;低优先级的消息不去重 |
服务端发送的规则
用户在客户端通过长连接发送聊天室消息,要满足以下条件:发出消息的这条连接在聊天室里;没有被聊天室禁言,聊天室开启了全员禁言时是所有者、管理员或在白名单中;没有被全局禁言;只有所有者和管理员可以发送高优先级的消息;每个用户每秒最多发送 5 条(突发 10 条)。
你的服务端以某个用户的身份或以系统的身份发送,不检查发送者是否在聊天室里、身份,聊天室内的禁言和全员禁言,以及全局禁言,任何发送者都可以发送高优先级的消息;也不检查附件地址是否符合运行策略 media_url_only 的限制。服务端只做以下检查:
| 检查 | 不通过时 |
|---|---|
| 消息的类型、内容和大小符合要求 | 400 invalid_argument、413 payload_too_large |
发送者(from)存在且未被删除 | 404 not_found |
| 发送者没有被平台封禁。被你的应用封禁的用户仍可以作为发送者 | 403 user_disabled |
| 聊天室存在且没有解散 | 404 not_found |
| 聊天室没有被封禁(包括被你封禁的) | 403 chatroom_disabled |
| 应用不是只读状态 | 403 app_unavailable |
| 按聊天室、按应用的发送限流 | 普通和高优先级返回 429 rate_limited;低优先级的消息被丢弃 |
限流:客户端和服务端发送的消息合计计算,规则见消息的优先级与下发:
| 限额 | 数值 | 超出时 |
|---|---|---|
| 每个聊天室每秒的普通和低优先级消息 | 运行策略 chatroom_msg_per_second,默认 40 条,可设 1 到 200 | 普通消息返回 429 rate_limited,details.reason 为 room_send_rate;低优先级的消息被丢弃,响应中 dropped 为 true |
| 每个聊天室每秒的高优先级消息 | 20 条 | 429 rate_limited,details.reason 为 room_send_rate |
| 应用全部聊天室每秒的消息 | 配额 chatroom_msg_per_sec_limit,默认 2000 条,三种优先级都计入 | 同上,details.reason 同样为 room_send_rate |
聊天室消息不计入单聊、群聊的消息配额 msg_per_min_limit。发送请求和其他 OpenAPI 请求一样计入应用每秒的调用次数。
{
"error": {
"code": "rate_limited",
"message": "聊天室消息太多,请稍后再试",
"details": { "reason": "room_send_rate", "retry_after_seconds": 1 },
"request_id": "KK4Z3DWPMCYBGRI7SYJK3OQQOL"
}
}发送前检查:通过以上检查后,消息依次经过以下两项检查,合计最多 500 毫秒:
- 内容安全:服务端发送的聊天室消息默认只按平台的规则检查;在内容安全中为聊天室消息开启了服务端提交的内容也检查时,还按你的词库和第三方审核检查。聊天室消息的检查最多 200 毫秒,第三方审核超时或出错时放行,之后再补审;低优先级的消息只按词库检查。不通过时返回
403 message_rejected,details.reason为sensitive_content等,见调用方看到的错误;命中替换规则的按替换后的内容发送。 - 发聊天室消息前回调:默认只对用户在客户端发送的消息调用,调用条件
vias包含openapi时,服务端发送的也会请求你的回调接收端。它在剩余的时间内等待接收端的响应,超时或失败时按这个回调自己的失败策略处理:策略为“拒绝”时返回403 message_rejected,details.reason为callback_unavailable。接收端拒绝时同样返回403 message_rejected,details.reason为app_rejected;改写的按改写后的body、ext发送,见操作方收到的错误。
响应中的 body、ext 是替换、改写之后实际发送的内容。用户在客户端发送的消息被改写时,长连接上 chatroom.send 的回复中同样带改写后的 body 和 ext,客户端据此更新本地显示的消息。
发送聊天室消息
以某个用户的身份或以系统的身份(没有发送者,客户端通常显示为系统通知)向聊天室发送一条消息。消息立即推给此刻在聊天室里的全部连接;普通和高优先级的消息同时写入最近的消息。消息的 via 为 openapi,客户端可以据此和 sender_role 显示“官方”“房管”等标识,不应信任 ext 中自称的身份。
/{org_name}/{app_name}/chatrooms/{room_id}/messages路径参数
org_name、app_name 见接入概述。
| 参数 | 类型 | 说明 |
|---|---|---|
room_id | String | 聊天室 ID |
请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
from | String | 否 | 发送者的用户名,必须是已存在的用户,不要求他在聊天室里。省略时以系统身份发送,消息的 sender 为 null、sender_type 为 system |
client_msg_id | String | 否 | 你为这条消息生成的唯一 ID,1 到 64 个可见 ASCII 字符,不能以 evt_、sys_ 开头。同一发送者(系统身份视为同一个发送者)在同一聊天室中,5 分钟内相同的 client_msg_id 只发送一次,见下文的重复提交。省略时由服务端生成一个 UUID,不能防止重复发送。低优先级的消息不去重 |
type | String | 是 | 消息类型:text、image、voice、video、file、location 或 custom,见消息类型 |
body | Object | 是 | 消息体,格式由 type 决定,与单聊、群聊消息相同,见消息类型。图片、语音、视频和文件先以用途 attachment 上传,再把地址写进 body,服务端只检查地址的格式 |
ext | Object | 否 | 扩展字段,你自定义的 JSON 对象,规则见扩展字段 ext。不需要时省略或传 null |
priority | String | 否 | 优先级:high、normal(默认)或 low,见消息的优先级与下发 |
type、body 和 ext 合计按服务端的 JSON 编码(去掉空白、UTF-8 字节)计算,不能超过运行策略 max_chatroom_message_bytes(默认 2048 字节)。请求中不能带 mentions、reply_to、push 等单聊、群聊消息专用的字段,带了返回 400 invalid_argument。
请求示例
以系统身份发送一条高优先级的通知:
curl -X POST "$IM_API/$ORG/$APP/chatrooms/100310941534519296/messages" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"client_msg_id": "notice-20261004-001",
"type": "text",
"body": { "text": "直播将在 5 分钟后开始" },
"ext": { "kind": "live_notice" },
"priority": "high"
}'以主播(所有者)的身份发送一条礼物消息:
curl -X POST "$IM_API/$ORG/$APP/chatrooms/100310941534519296/messages" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"from": "zhangsan",
"client_msg_id": "gift-8f3a91",
"type": "custom",
"body": { "event": "gift", "gift_id": "rocket", "count": 1 },
"ext": { "combo": 3 },
"priority": "high"
}'响应
成功返回 201 Created,响应体为发送的聊天室消息对象,另加一个字段:
| 字段 | 类型 | 说明 |
|---|---|---|
dropped | Boolean | 低优先级的消息是否因限流被丢弃。新发送的消息为 false |
以系统身份发送的响应:
{
"room_id": "100310941534519296",
"message_id": "100312324253941760",
"client_msg_id": "notice-20261004-001",
"sender": null,
"sender_type": "system",
"sender_nickname": null,
"sender_avatar_url": null,
"sender_role": null,
"type": "text",
"body": { "text": "直播将在 5 分钟后开始" },
"ext": { "kind": "live_notice" },
"priority": "high",
"via": "openapi",
"created_at": "2026-10-04T19:25:21.815Z",
"dropped": false
}以用户身份发送的响应:
{
"room_id": "100310941534519296",
"message_id": "100312466948358144",
"client_msg_id": "gift-8f3a91",
"sender": "zhangsan",
"sender_type": "user",
"sender_nickname": "张三",
"sender_avatar_url": "https://cdn.example.com/avatar/zhangsan.png",
"sender_role": "owner",
"type": "custom",
"body": { "event": "gift", "gift_id": "rocket", "count": 1 },
"ext": { "combo": 3 },
"priority": "high",
"via": "openapi",
"created_at": "2026-10-04T19:25:55.836Z",
"dropped": false
}重复提交:5 分钟内用相同的 client_msg_id 重试时返回 200 OK,消息不会再推送一次,响应中的 message_id 和 created_at 是第一次发送的值。请以这两个字段为准:响应中的其他字段取自这次请求,发送者的字段(sender 等)可能为空。
低优先级的消息被丢弃:超出聊天室每秒的消息额度时返回 200 OK,dropped 为 true,message_id 和 created_at 为 null,消息没有发出。点赞这类消息丢弃无妨,不需要重试:
{
"client_msg_id": null,
"created_at": null,
"dropped": true,
"message_id": null,
"priority": "low",
"room_id": "100311027198984192"
}错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 400 | invalid_argument | details.reason 为 unknown_type:不支持的消息类型,包括 tip |
| 400 | invalid_argument | details.reason 为 invalid_body:body 或 ext 不符合要求,details.field 指出字段 |
| 400 | invalid_argument | details.reason 为 invalid_client_msg_id:client_msg_id 不是 1 到 64 个可见 ASCII 字符 |
| 400 | invalid_argument | details.reason 为 reserved_client_msg_id:client_msg_id 以 evt_ 或 sys_ 开头 |
| 400 | invalid_argument | details.reason 为 invalid_priority:priority 不是 high、normal、low 之一 |
| 403 | user_disabled | 发送者已被平台封禁,details.disabled_by 为 platform |
| 403 | chatroom_disabled | 聊天室已被封禁,details.disabled_by 为 tenant(你封禁的)或 platform(平台封禁的) |
| 403 | message_rejected | 消息被发送前检查拒绝:内容安全拒绝时 details.reason 为 sensitive_content 或 provider_block(聊天室消息的第三方审核超时一律放行,不会返回 check_timeout);发聊天室消息前回调拒绝时为 app_rejected 或 callback_unavailable,另有 details.app_reason,message 为接收端给出的提示 |
| 403 | app_unavailable | 应用处于只读状态,不能发送消息 |
| 404 | not_found | 聊天室不存在或已解散;from 指定的用户不存在 |
| 413 | payload_too_large | 消息超过应用的大小上限,details.max_bytes 为上限 |
| 429 | rate_limited | details.reason 为 room_send_rate:超过聊天室或应用每秒的消息额度 |
| 500 | internal | details.reason 为 dependency_unavailable:消息暂时无法推送,没有发出。请按 Retry-After 响应头等待后,用同一个 client_msg_id 重试 |
查询最近的消息
返回聊天室最近的消息,按时间从早到晚排列,不要求任何用户在聊天室里。只包含普通和高优先级的消息,不含低优先级的消息和已撤回的消息,最多保留 24 小时,保存的条数由运行策略 chatroom_history_size 决定(默认 50 条),见最近的消息。这不是完整的历史记录,不能向前翻页。
/{org_name}/{app_name}/chatrooms/{room_id}/messages路径参数
org_name、app_name 见接入概述。
| 参数 | 类型 | 说明 |
|---|---|---|
room_id | String | 聊天室 ID |
查询参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
limit | Number | 否 | 最多返回最近的多少条,正整数。默认和最大值都为运行策略 chatroom_history_size,超过时按它返回 |
一次响应中消息合计不超过 1 MB,超出时舍去较早的几条。
请求示例
curl -X GET "$IM_API/$ORG/$APP/chatrooms/100310941534519296/messages?limit=3" \
-H "Authorization: Bearer $APP_TOKEN"响应
成功返回 200 OK,items 中每项为一条聊天室消息对象,按时间从早到晚排列;没有消息时为空数组。
{
"items": [
{
"room_id": "100310941534519296",
"message_id": "100312466755420160",
"client_msg_id": "991d51c8-0e88-43d1-a830-ee3f160075cb",
"sender": "zhaoliu",
"sender_type": "user",
"sender_nickname": "赵六",
"sender_avatar_url": "https://cdn.example.com/avatar/zhaoliu.png",
"sender_role": "member",
"type": "text",
"body": { "text": "感谢大家的支持" },
"ext": null,
"priority": "normal",
"via": "openapi",
"created_at": "2026-10-04T19:25:55.790Z"
},
{
"room_id": "100310941534519296",
"message_id": "100312466948358144",
"client_msg_id": "gift-8f3a91",
"sender": "zhangsan",
"sender_type": "user",
"sender_nickname": "张三",
"sender_avatar_url": "https://cdn.example.com/avatar/zhangsan.png",
"sender_role": "owner",
"type": "custom",
"body": { "event": "gift", "gift_id": "rocket", "count": 1 },
"ext": { "combo": 3 },
"priority": "high",
"via": "openapi",
"created_at": "2026-10-04T19:25:55.836Z"
},
{
"room_id": "100310941534519296",
"message_id": "100312501224210432",
"client_msg_id": "c-97ff80f040e8",
"sender": "sunqi",
"sender_type": "user",
"sender_nickname": "孙七",
"sender_avatar_url": "https://cdn.example.com/avatar/sunqi.png",
"sender_role": "member",
"type": "text",
"body": { "text": "唱得太好了!" },
"ext": null,
"priority": "normal",
"via": "client",
"created_at": "2026-10-04T19:26:04.008Z"
}
]
}错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 400 | invalid_argument | limit 不是正整数 |
| 404 | not_found | 聊天室不存在或已解散 |
| 500 | internal | details.reason 为 dependency_unavailable:暂时无法读取,按 Retry-After 响应头等待后重试 |
撤回聊天室消息
撤回聊天室中的一条消息,不受发送者和发送时间的限制。撤回后:
- 这条消息从最近的消息中删除;
- 聊天室的在线成员实时收到撤回的通知(其中
recalled_by为null,role为server),客户端把这条消息从界面上移除。
消息已经推给在线成员,撤回只是通知客户端不再显示,并不能保证所有人都没有看到。
不在最近的消息中的消息:低优先级的消息、已经超出保存条数或 24 小时的消息,以及已经撤回过的消息,都不在最近的消息中。服务端撤回它们时无法确认这条消息是否存在,仍然照常推送撤回的通知,返回 changed 为 true;客户端会忽略不认识的消息 ID。因此重复撤回同一条消息也会再推送一次通知,changed 同样为 true。
被封禁的聊天室也可以撤回。
/{org_name}/{app_name}/chatrooms/{room_id}/messages/{message_id}/recall路径参数
org_name、app_name 见接入概述。
| 参数 | 类型 | 说明 |
|---|---|---|
room_id | String | 聊天室 ID |
message_id | String | 要撤回的消息 ID |
请求体
请求体可以省略。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
reason | String | 否 | 撤回原因,最长 256 个字符,不能包含控制字符。只记录在控制台的操作日志中,不会展示给用户 |
请求示例
curl -X POST "$IM_API/$ORG/$APP/chatrooms/100310941534519296/messages/100312501224210432/recall" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reason": "含有违规内容"
}'响应
成功返回 200 OK:
| 字段 | 类型 | 说明 |
|---|---|---|
changed | Boolean | 是否推送了撤回的通知。只有极少数情况下(同一条消息被几个请求同时撤回)为 false |
{
"changed": true
}错误
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 400 | invalid_argument | reason 超过 256 个字符或包含控制字符 |
| 404 | not_found | 聊天室不存在或已解散;message_id 的格式不对 |
| 500 | internal | details.reason 为 dependency_unavailable:暂时无法撤回,按 Retry-After 响应头等待后重试 |
数据结构
聊天室消息对象
推送给客户端的消息、发送的响应和最近的消息中,每条消息的格式相同。
| 字段 | 类型 | 说明 |
|---|---|---|
room_id | String | 聊天室 ID |
message_id | String | 消息 ID,由服务端生成 |
client_msg_id | String | 发送方给出的 client_msg_id;服务端发送时没有给出的,为服务端生成的 UUID;客户端发送的低优先级消息可以没有,为 null |
sender | String | 发送者的用户名;系统消息为 null |
sender_type | String | 发送者类型:user 用户,system 系统 |
sender_nickname | String | 发送时发送者的昵称,之后不随资料的变化而更新;系统消息为 null |
sender_avatar_url | String | 发送时发送者的头像地址;系统消息为 null |
sender_role | String | 发送时发送者在聊天室中的身份:owner、admin 或 member;系统消息为 null |
type | String | 消息类型,见消息类型 |
body | Object | 消息体 |
ext | Object | 扩展字段,没有时为 null |
priority | String | 优先级:high、normal 或 low |
via | String | 发送入口:client 用户在客户端发送,openapi 你的服务端发送,console 在控制台发送,system 由本服务自动发送 |
created_at | String | 发送时间。同一聊天室中消息的时间只是大致有序,客户端按到达的顺序显示即可 |
{
"room_id": "100310941534519296",
"message_id": "100312324354605056",
"client_msg_id": "b1f3c0de-5e7a-4f55-9c1d-2a8e6f0b9d11",
"sender": "lisi",
"sender_type": "user",
"sender_nickname": "李四",
"sender_avatar_url": "https://cdn.example.com/avatar/lisi.png",
"sender_role": "admin",
"type": "text",
"body": { "text": "欢迎大家,开播后请文明发言" },
"ext": null,
"priority": "normal",
"via": "openapi",
"created_at": "2026-10-04T19:25:21.839Z"
}