# XuqmGroup Server 联调接口文档 > 最后更新:2026-04-28 ## 线上入口 | 服务 | 地址 | 说明 | |------|------|------| | 租户服务 | `https://dev.xuqinmin.com/api/` | 认证、应用、子账号、运营平台 | | IM HTTP | `https://dev.xuqinmin.com/api/im/` | IM 登录、消息发送、撤回、历史消息 | | IM WebSocket | `wss://dev.xuqinmin.com/ws/im` | 实时消息 | | 文件服务 | `https://file.dev.xuqinmin.com/api/file/` | 文件上传、下载、缩略图 | | App 更新 | `https://dev.xuqinmin.com/api/v1/updates/` | 原生版本管理 | | RN 热更新 | `https://dev.xuqinmin.com/api/v1/rn/` | Bundle 热更新 | ## ID 约定 这套工程里同时存在两种“应用标识”,不要混用: | 名称 | 含义 | 常见位置 | |------|------|----------| | `tenant appId` | 租户平台应用主键,`tenant-service` 的 `/api/apps/{id}`、`/api/apps/{appId}/services` 使用它 | 租户平台、服务配置页 | | `IM appKey` | IM 业务域作用域标识,`im-service` 的管理接口和消息接口虽然参数名仍叫 `appId`,但实际传的是这个值 | IM 管理页、IM HTTP 接口 | 结论: - `tenant-platform` 的“服务配置”只认租户 `app.id` - `tenant-platform` 的“IM 管理”必须带 `appKey` - `im-service` 代码里沿用旧参数名 `appId`,但这是历史命名,调用方传的是 `appKey` ## 初始化管理员账号 | 字段 | 值 | |------|----| | 用户名 | `admin` | | 初始密码 | `Admin@123456` | | 登录接口 | `POST /api/auth/ops/login` | ## 统一响应 ```json { "code": 200, "status": "0", "data": {}, "message": "success" } ``` ## 常见错误码 | `code` | `status` | 说明 | |--------|----------|------| | `200` | `"0"` | 成功 | | `400` | `"1"` | 参数校验失败或请求不合法 | | `401` | `"1"` | 未登录、Token 无效或已过期 | | `403` | `"1"` | 无权限访问 | | `500` | `"1"` | 服务端内部错误 | ## 鉴权规则 | 场景 | 鉴权方式 | |------|----------| | 租户平台接口 | `Authorization: Bearer ` | | 运营平台接口 | `Authorization: Bearer ` | | IM HTTP 接口 | `Authorization: Bearer ` | | IM WebSocket | `?token=` | | App 更新检查 | 无需登录 | | RN 更新检查 | 无需登录 | | Bundle 下载 | 无需登录 | ## 核心接口清单 ### tenant-service | 方法 | 路径 | 鉴权 | 说明 | |------|------|------|------| | GET | `/api/auth/captcha` | 否 | 获取图形验证码 | | POST | `/api/auth/send-email-code` | 否 | 发送邮箱验证码 | | POST | `/api/auth/register` | 否 | 注册主账号 | | POST | `/api/auth/login` | 否 | 租户登录 | | POST | `/api/auth/forgot-password` | 否 | 发送找回密码邮件 | | POST | `/api/auth/reset-password` | 否 | 重置密码 | | GET | `/api/apps` | 是 | 应用列表 | | GET | `/api/apps/{id}` | 是 | 应用详情 | | POST | `/api/apps` | 是 | 创建应用 | | PUT | `/api/apps/{id}` | 是 | 更新应用 | | DELETE | `/api/apps/{id}` | 是 | 删除应用 | | GET | `/api/apps/{appId}/services` | 是 | 服务列表 | | POST | `/api/apps/{appId}/services/toggle` | 是 | 开关服务 | | POST | `/api/apps/{appId}/services/{id}/regenerate-key` | 是 | 重新生成服务密钥 | | GET | `/api/sub-accounts` | 是 | 子账号列表 | | POST | `/api/sub-accounts/send-verify-code` | 是 | 子账号邮箱验证码 | | POST | `/api/sub-accounts/verify-email` | 是 | 校验子账号邮箱 | | POST | `/api/sub-accounts` | 是 | 创建子账号 | | DELETE | `/api/sub-accounts/{id}` | 是 | 禁用子账号 | | POST | `/api/auth/ops/login` | 否 | 运营管理员登录 | | GET | `/api/ops/tenants` | 是 | 运营租户列表 | | POST | `/api/ops/tenants/{id}/toggle-status` | 是 | 租户启停 | | GET | `/api/ops/statistics` | 是 | 统计面板 | ### im-service | 方法 | 路径 | 鉴权 | 说明 | |------|------|------|------| | POST | `/api/im/auth/login` | 否 | 获取 IM Token;需要 `X-App-Timestamp` / `X-App-Nonce` / `X-App-Signature` | | GET | `/api/im/accounts/{userId}` | 是 | 查询用户资料 | | PUT | `/api/im/accounts/{userId}` | 是 | 更新自己的资料 | | GET | `/api/im/accounts/search` | 否 | 搜索账号 | | POST | `/api/im/accounts/import` | 是 | 导入单个账号 | | POST | `/api/im/accounts/import/batch` | 是 | 批量导入账号 | | DELETE | `/api/im/accounts/{userId}` | 是 | 删除账号 | | GET | `/api/im/accounts/{userId}/exists` | 是 | 检查账号是否存在 | | GET | `/api/im/groups/{groupId}/members` | 是 | 查询群成员列表 | | GET | `/api/im/groups/{groupId}/members/search` | 是 | 搜索群成员 | | POST | `/api/im/messages/send` | 是 | 发送消息(TEXT / IMAGE / AUDIO / VIDEO / FILE / LOCATION / CUSTOM / NOTIFY / RICH_TEXT / CALL_AUDIO / CALL_VIDEO / FORWARD / QUOTE / MERGE) | | GET | `/api/im/messages/search` | 是 | 云端消息搜索 | | PUT | `/api/im/messages/{id}` | 是 | 编辑自己发送的文本消息 | | POST | `/api/im/messages/{id}/revoke` | 是 | 撤回消息 | | GET | `/api/im/messages/history/{toId}` | 是 | 查询历史消息 | | WS | `/ws/im` | IM Token | 建立实时连接 | ### push-service | 方法 | 路径 | 鉴权 | 说明 | |------|------|------|------| | POST | `/api/push/register` | 是 | 注册设备 token | | POST | `/api/push/receive-push` | 是 | 开启或关闭接收推送 | | POST | `/api/push/send` | 是 | 发送推送通知 | ### file-service | 方法 | 路径 | 鉴权 | 说明 | |------|------|------|------| | POST | `/api/file/upload` | 是 | 文件上传,按 SHA-256 去重 | | GET | `/api/file/{hash}` | 否 | 按 hash 获取文件 | | GET | `/api/file/{hash}/thumbnail` | 否 | 按 hash 获取缩略图 | ### update-service | 方法 | 路径 | 鉴权 | 说明 | |------|------|------|------| | GET | `/api/v1/updates/app/check` | 否 | 检查 App 更新 | | POST | `/api/v1/updates/app/upload` | 是 | 上传 App 版本,支持即时发布 / 定时发布 / 市场提交配置;Harmony 版本仅保存市场链接,不提供本地安装包下载 | | POST | `/api/v1/updates/app/{id}/publish` | 是 | 发布 App 版本 | | GET | `/api/v1/updates/app/list` | 是 | App 版本列表 | | GET | `/api/v1/updates/files/apk/{filename}` | 否 | 下载 APK | | GET | `/api/v1/rn/update/check` | 否 | 检查 RN 热更新 | | POST | `/api/v1/rn/upload` | 是 | 上传 Bundle | | POST | `/api/v1/rn/{id}/publish` | 是 | 发布 Bundle | | GET | `/api/v1/rn/files/{appId}/{platform}/{moduleId}` | 否 | 下载 Bundle | 说明:这里的 `appId` 按 `appKey` 解析。当前 demo 默认使用 `ak_demo_chat`,`tenant-service` 会优先复用数据库里已有的应用;如果没有,会自动补一条默认 demo 应用和基础服务配置。`POST /api/im/auth/login` 还要求 demo-service 通过 AppSecret 生成签名头再转发给 IM 服务。 ## curl 示例 ### 运营平台登录 ```bash curl -X POST 'https://dev.xuqinmin.com/api/auth/ops/login' \ -H 'Content-Type: application/json' \ -d '{"username":"admin","password":"Admin@123456"}' ``` ### App 更新检查 ```bash curl 'https://dev.xuqinmin.com/api/v1/updates/app/check?appId=ak_demo_chat&platform=ANDROID¤tVersionCode=1' curl 'https://dev.xuqinmin.com/api/v1/updates/app/check?appId=ak_demo_chat&platform=HARMONY¤tVersionCode=1' ``` Harmony 平台只跳转应用市场,不提供本地安装包下载。 ### RN 热更新检查 ```bash curl 'https://dev.xuqinmin.com/api/v1/rn/update/check?appId=ak_demo_chat&platform=ANDROID&moduleId=chat-home¤tVersion=1.0.0' ``` ### IM 登录 ```bash curl -X POST 'https://dev.xuqinmin.com/api/im/auth/login?appId=ak_demo_chat&userId=demo_alice' ``` 返回示例中的 `data` 会同时包含 `token` 和 `expiresAt`,用于客户端提前做静默续签。 ### Demo IM 刷新 ```bash curl -X POST 'https://dev.xuqinmin.com/api/demo/auth/refresh-im?appId=ak_demo_chat' \ -H 'Authorization: Bearer ' ``` 该接口会基于 demo 登录态重新签发 IM token,并返回新的 `expiresAt`。 ### IM 会话与关系链 ```bash curl 'https://dev.xuqinmin.com/api/im/accounts/user_001?appId=ak_demo_chat' curl -X POST 'https://dev.xuqinmin.com/api/im/accounts/import?appId=ak_demo_chat' \ -H 'Content-Type: application/json' \ -d '{"userId":"user_001","nickname":"Alice"}' curl -X POST 'https://dev.xuqinmin.com/api/im/accounts/import/batch?appId=ak_demo_chat' \ -H 'Content-Type: application/json' \ -d '[{"userId":"user_001"},{"userId":"user_002"}]' curl -X DELETE 'https://dev.xuqinmin.com/api/im/accounts/user_001?appId=ak_demo_chat' curl 'https://dev.xuqinmin.com/api/im/accounts/user_001/exists?appId=ak_demo_chat' curl 'https://dev.xuqinmin.com/api/im/conversations?appId=ak_demo_chat' curl -X PUT 'https://dev.xuqinmin.com/api/im/conversations/user_002/pinned?appId=ak_demo_chat&chatType=SINGLE&pinned=true' curl -X PUT 'https://dev.xuqinmin.com/api/im/conversations/user_002/draft?appId=ak_demo_chat&chatType=SINGLE&draft=hello' curl -X DELETE 'https://dev.xuqinmin.com/api/im/conversations/user_002?appId=ak_demo_chat&chatType=SINGLE' curl 'https://dev.xuqinmin.com/api/im/groups?appId=ak_demo_chat' curl 'https://dev.xuqinmin.com/api/im/groups/public?appId=ak_demo_chat&keyword=demo' curl 'https://dev.xuqinmin.com/api/im/groups/search?appId=ak_demo_chat&keyword=demo&size=20' curl 'https://dev.xuqinmin.com/api/im/groups/group_001/members?appId=ak_demo_chat' curl 'https://dev.xuqinmin.com/api/im/groups/group_001/members/search?appId=ak_demo_chat&keyword=demo&size=20' curl 'https://dev.xuqinmin.com/api/im/messages/search?appId=ak_demo_chat&keyword=hello&page=0&size=20' curl 'https://dev.xuqinmin.com/api/im/admin/webhooks?appId=ak_demo_chat' curl -X POST 'https://dev.xuqinmin.com/api/im/groups/group_001/join-requests?appId=ak_demo_chat&remark=申请加入' curl 'https://dev.xuqinmin.com/api/im/groups/group_001/join-requests?appId=ak_demo_chat' curl -X POST 'https://dev.xuqinmin.com/api/im/groups/group_001/join-requests/req_001/accept?appId=ak_demo_chat' curl -X POST 'https://dev.xuqinmin.com/api/im/groups/group_001/join-requests/req_001/reject?appId=ak_demo_chat' curl 'https://dev.xuqinmin.com/api/im/blacklist?appId=ak_demo_chat' curl 'https://dev.xuqinmin.com/api/im/friend-requests?appId=ak_demo_chat&direction=incoming' ``` ### IM 管理后台接口 ```bash curl 'https://dev.xuqinmin.com/api/im/admin/users?appId=ak_demo_chat&page=0&size=20' curl 'https://dev.xuqinmin.com/api/im/admin/groups?appId=ak_demo_chat' curl 'https://dev.xuqinmin.com/api/im/admin/messages?appId=ak_demo_chat&userA=user_001&userB=user_002&page=0&size=20' curl 'https://dev.xuqinmin.com/api/im/admin/operation-logs?appId=ak_demo_chat&page=0&size=20' curl -X POST 'https://dev.xuqinmin.com/api/im/admin/messages/msg_001/revoke?appId=ak_demo_chat' curl -X DELETE 'https://dev.xuqinmin.com/api/im/admin/groups/group_001' curl 'https://dev.xuqinmin.com/api/im/admin/friend-requests?appId=ak_demo_chat' curl -X POST 'https://dev.xuqinmin.com/api/im/admin/friend-requests/req_001/accept?appId=ak_demo_chat' curl -X POST 'https://dev.xuqinmin.com/api/im/admin/blacklist?appId=ak_demo_chat' \ -H 'Content-Type: application/json' \ -d '{"userId":"user_001","blockedUserId":"user_002"}' curl 'https://dev.xuqinmin.com/api/im/admin/groups/group_001/members?appId=ak_demo_chat' curl 'https://dev.xuqinmin.com/api/im/admin/groups/group_001/join-requests?appId=ak_demo_chat' curl -X POST 'https://dev.xuqinmin.com/api/im/admin/groups/group_001/join-requests/req_001/accept?appId=ak_demo_chat' curl 'https://dev.xuqinmin.com/api/im/admin/keyword-filters?appId=ak_demo_chat' curl 'https://dev.xuqinmin.com/api/im/admin/global-mute?appId=ak_demo_chat' ``` ### IM Webhook 回调 IM 服务会在消息、好友和已读等事件发生后,以 `POST` 方式向你配置的回调地址推送事件。 请求头: - `Content-Type: application/json` - `X-App-Id`: 应用 `appId` - `X-App-Timestamp`: 请求时间戳 - `X-App-Nonce`: 随机串 - `X-App-Signature`: 签名结果 签名规则: ```text HMAC-SHA256(appSecret, appId + "\n" + timestamp + "\n" + nonce + "\n" + sha256(body)) ``` 统一请求体结构: ```json { "callbackId": "uuid", "callbackType": "message", "callbackEvent": "message.sent", "requestTime": 1714360000000, "payload": {}, "signature": null, "appId": "ak_demo_chat" } ``` 字段说明: | 字段 | 说明 | |------|------| | `callbackId` | 回调唯一 ID,用于去重和排障 | | `callbackType` | 回调大类,例如 `message`、`friend`、`group`、`blacklist` | | `callbackEvent` | 具体事件,例如 `message.sent`、`friend.request.sent` | | `requestTime` | 毫秒时间戳 | | `payload` | 事件数据,结构随事件变化 | | `signature` | 预留字段,当前由请求头承载 | | `appId` | 回调所属应用 ID | `payload` 会根据事件类型变化: | 事件 | payload 类型 | 说明 | |------|-------------|------| | `message.sent` | `ImMessageEntity` | 发送消息成功后触发 | | `message.revoked` | `ImMessageEntity` | 撤回消息后触发 | | `message.edited` | `ImMessageEntity` | 编辑文本消息后触发 | | `message.read` | `MessageReadCallbackPayload` | 已读回执同步后触发 | | `friend.request.sent` | `FriendRequestCallbackPayload` | 好友申请创建后触发 | | `friend.request.accepted` | `FriendRequestCallbackPayload` | 好友申请通过后触发 | | `friend.request.rejected` | `FriendRequestCallbackPayload` | 好友申请拒绝后触发 | | `group.join.request.sent` | `GroupJoinRequestCallbackPayload` | 入群申请创建后触发 | | `group.join.request.accepted` | `GroupJoinRequestCallbackPayload` | 入群申请通过后触发 | | `group.join.request.rejected` | `GroupJoinRequestCallbackPayload` | 入群申请拒绝后触发 | | `blacklist.added` | `BlacklistCallbackPayload` | 黑名单记录新增后触发 | | `blacklist.removed` | `BlacklistCallbackPayload` | 黑名单记录移除后触发 | 各 payload 字段如下: #### `MessageReadCallbackPayload` ```json { "appId": "ak_demo_chat", "readerId": "user_001", "peerId": "user_002", "groupId": null, "chatType": "SINGLE", "readAt": 1714360000000, "messageIds": ["msg_001", "msg_002"] } ``` #### `FriendRequestCallbackPayload` ```json { "appId": "ak_demo_chat", "requestId": "req_001", "fromUserId": "user_001", "toUserId": "user_002", "remark": "hi", "status": "PENDING", "reviewedAt": null } ``` #### `GroupJoinRequestCallbackPayload` ```json { "appId": "ak_demo_chat", "requestId": "req_001", "groupId": "group_001", "groupName": "技术群", "requesterId": "user_003", "remark": "申请加入", "status": "PENDING", "reviewedAt": null } ``` #### `BlacklistCallbackPayload` ```json { "appId": "ak_demo_chat", "id": "blk_001", "userId": "user_001", "blockedUserId": "user_002", "action": "ADD", "createdAt": 1714360000000 } ``` 说明: - 回调发送失败不会影响主流程,只记录日志。 - 当前版本的回调配置是按应用维度管理的,多个地址会同时接收同一事件。 - 新增的好友、入群、黑名单回调都复用同一 envelope 和签名规则,payload 字段按上表中的类型序列化。 - 接收方建议用 `callbackId` 做幂等去重,避免重复投递造成重复处理。 - 服务端当前不做重试队列,失败只会在调用端记录日志。 示例验签: ```ts import crypto from 'crypto' export function verifyWebhook({ appId, timestamp, nonce, body, signature, appSecret, }: { appId: string timestamp: string nonce: string body: string signature: string appSecret: string }) { const bodyHash = crypto.createHash('sha256').update(body, 'utf8').digest('hex') const payload = `${appId}\n${timestamp}\n${nonce}\n${bodyHash}` const expected = crypto.createHmac('sha256', appSecret).update(payload, 'utf8').digest('hex') return expected === signature } ``` ### 好友申请 / 黑名单 ```bash curl -X POST 'https://dev.xuqinmin.com/api/im/friend-requests?appId=ak_demo_chat&toUserId=user_002&remark=hi' curl -X POST 'https://dev.xuqinmin.com/api/im/friend-requests/req_001/accept?appId=ak_demo_chat' curl -X POST 'https://dev.xuqinmin.com/api/im/friend-requests/req_001/reject?appId=ak_demo_chat' curl 'https://dev.xuqinmin.com/api/im/groups/group_001/join-requests?appId=ak_demo_chat' curl -X POST 'https://dev.xuqinmin.com/api/im/groups/group_001/join-requests?appId=ak_demo_chat&remark=申请加入' curl -X POST 'https://dev.xuqinmin.com/api/im/groups/group_001/join-requests/req_001/accept?appId=ak_demo_chat' curl -X POST 'https://dev.xuqinmin.com/api/im/groups/group_001/join-requests/req_001/reject?appId=ak_demo_chat' curl -X POST 'https://dev.xuqinmin.com/api/im/blacklist?appId=ak_demo_chat&blockedUserId=user_002' curl -X DELETE 'https://dev.xuqinmin.com/api/im/blacklist?appId=ak_demo_chat&blockedUserId=user_002' ``` ### IM 历史过滤查询 ```bash curl 'https://dev.xuqinmin.com/api/im/messages/history/user_002?appId=ak_demo_chat&page=0&size=20&keyword=hello&msgType=TEXT' curl 'https://dev.xuqinmin.com/api/im/messages/group-history/group_001?appId=ak_demo_chat&page=0&size=20&keyword=user_002&startTime=2026-04-27T00:00:00&endTime=2026-04-27T23:59:59' ``` 支持的筛选参数:`keyword`、`msgType`、`startTime`、`endTime`。 ### IM 媒体消息 ```bash curl -X POST 'https://file.dev.xuqinmin.com/api/file/upload' \ -H 'Authorization: Bearer ' \ -F 'file=@image.jpg' curl -X POST 'https://im.dev.xuqinmin.com/api/im/messages/send?appId=ak_demo_chat' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -d '{"toId":"user_002","chatType":"SINGLE","msgType":"IMAGE","content":"{\"url\":\"https://file.dev.xuqinmin.com/api/file/abc\"}"}' ``` 当前 `im-service` 的消息发送接口已经支持 `AUDIO`、`LOCATION`、`CUSTOM`、`RICH_TEXT`、`FORWARD`、`QUOTE`、`MERGE`、`CALL_AUDIO`、`CALL_VIDEO` 这些通用类型,客户端只需按协议传入对应 JSON 内容即可。 群聊消息在历史查询和实时推送里会携带 `groupReadCount`,用于展示 `N 人已读`。