9.3 KiB
9.3 KiB
02 — iLink 协议完整参考
本文档是对 iLink Bot API 的完整整理,供实现协议层时对照查阅。 来源:腾讯官方包
@tencent-weixin/openclaw-weixin的逆向分析、Java SDK 实现、多个第三方适配器实践。字段级细节以实测为准。
1. 基本信息
| 项 | 值 |
|---|---|
| API 根地址 | https://ilinkai.weixin.qq.com |
| CDN 地址 | https://novac2c.cdn.weixin.qq.com/c2c |
| 协议 | HTTPS + JSON |
| 收消息模式 | HTTP 长轮询(无 Webhook,无需公网 IP) |
| 鉴权 | Authorization: Bearer <bot_token> |
2. 端点总表
| Endpoint | Method | 功能 | 需要鉴权 |
|---|---|---|---|
/ilink/bot/get_bot_qrcode |
GET | 获取登录二维码(?bot_type=3) |
否 |
/ilink/bot/get_qrcode_status |
GET | 轮询扫码状态(?qrcode=xxx) |
否 |
/ilink/bot/getupdates |
POST | 长轮询收消息(核心) | 是 |
/ilink/bot/sendmessage |
POST | 发送消息(文本/图片/文件/视频/语音) | 是 |
/ilink/bot/getconfig |
POST | 获取配置(typing_ticket 等) | 是 |
/ilink/bot/sendtyping |
POST | 发送「正在输入」状态 | 是 |
/ilink/bot/getuploadurl |
POST | 获取 CDN 预签名上传地址 | 是 |
3. 通用请求头
登录后所有请求的固定头:
Content-Type: application/json
AuthorizationType: ilink_bot_token
Authorization: Bearer <bot_token>
X-WECHAT-UIN: <base64(十进制字符串(随机uint32))>
X-WECHAT-UIN:每次请求生成一个随机 uint32 → 转十进制字符串 → base64 编码。每次都不一样,起防重放作用。- 扫码登录阶段(
get_qrcode_status)有实现带iLink-App-ClientVersion: 1头。
4. 登录流程(一次性扫码绑定)
4.1 时序
开发者 iLink 服务器 微信用户
│── GET get_bot_qrcode ──▶│ │
│◀── { qrcode, url } ─────│ │
│ │◀──── 用户扫码 ───────│
│── GET get_qrcode_status ─▶│ (长轮询/定时轮询) │
│◀── { status:"confirmed", │ │
│ bot_token, ... } ──│ │
│
▼ 持久化 bot_token,后续所有请求 Bearer 鉴权
4.2 获取二维码
GET /ilink/bot/get_bot_qrcode?bot_type=3
响应:
{
"qrcode": "xxx",
"qrcode_img_content": "https://liteapp.weixin.qq.com/q/..."
}
qrcode:QR 标识符,轮询状态时用qrcode_img_content:二维码图片 URL,可在终端渲染(如qrcode-terminal)或浏览器打开给用户扫bot_type=3是官方包源码中硬编码的值,含义未公开,照抄即可
4.3 轮询扫码状态
GET /ilink/bot/get_qrcode_status?qrcode=<qrcode>
状态流转:wait → scaned → confirmed(注意官方拼写是 scaned)。
确认后响应(关键凭据):
{
"status": "confirmed",
"bot_token": "44b9b8ec@im.bot:060000b7...",
"ilink_bot_id": "44b9b8ec@im.bot",
"ilink_user_id": "o9cq809L...@im.wechat",
"baseurl": "https://ilinkai.weixin.qq.com"
}
bot_token是之后所有 API 调用的鉴权凭据,一次扫码长期有效(具体有效期官方未公布,社区观察为长期;过期会收到 errcode=-14,需重新扫码)- 建议把
bot_token、ilink_bot_id、ilink_user_id、baseurl全部持久化 - 轮询建议间隔 1s,整体超时给 5~8 分钟
5. 收消息:长轮询
5.1 请求
POST /ilink/bot/getupdates
{
"get_updates_buf": "<上次返回的游标,首次为空字符串>",
"base_info": { "channel_version": "1.0.2" }
}
5.2 响应
{
"ret": 0,
"msgs": [ /* WeixinMessage[],见第 7 节 */ ],
"get_updates_buf": "Ck1...",
"longpolling_timeout_ms": 35000
}
5.3 机制要点
- 服务器 hold 住连接最多约 30~35 秒(
longpolling_timeout_ms会告知),有新消息立即返回,无消息超时返回空msgs - HTTP 客户端超时必须设得比
longpolling_timeout_ms大(建议 +10s 余量) get_updates_buf是同步游标(类似 Telegram getUpdates 的 offset):- 每次请求带上次返回的值
- 收到响应后立刻持久化,否则重启后会重复收消息
- 返回中没有该字段时保持旧值
- HTTP 超时/网络错误视为「本轮无新消息」,直接重试,不要中断循环
5.4 失败恢复与退避(来自 Java SDK 的实战策略)
| 情况 | 处理 |
|---|---|
errcode = -14(会话过期 / token 失效) |
该账号进入暂停窗口(SDK 默认 1 小时),期间停止轮询和发送;提示用户重新扫码 |
| 其他失败 | 2s 后快速重试;连续失败 3 次后进入 30s 退避 |
| HTTP 超时 | 视为无新消息,立即进入下一轮 |
响应带 longpolling_timeout_ms |
动态调整下一轮轮询超时 |
6. 发消息
POST /ilink/bot/sendmessage
{
"msg": {
"to_user_id": "o9cq809L...@im.wechat",
"client_id": "unique-id-123",
"message_type": 2,
"message_state": 2,
"context_token": "CK3E...",
"item_list": [
{ "type": 1, "text_item": { "text": "你好!我是你的 AI。" } }
]
}
}
字段说明:
| 字段 | 说明 |
|---|---|
to_user_id |
收件人,取入站消息的 from_user_id |
client_id |
客户端生成的去重 ID(如 UUID),防止重发 |
message_type |
2 = Bot 发出的消息(入站用户消息是 1) |
message_state |
2 = FINISH 完成态(非流式)。协议还有 NEW(0?) → GENERATING → FINISH 的三段式状态,可用于流式分片发送(Java SDK 的 sendTextStream 即分片发送,但注意那不是 LLM token 流,而是把长文本切成多条消息) |
context_token |
必填,从要回复的那条入站消息原样取出 |
item_list |
消息体,文本见上;媒体 item 构造见 03 文档 |
7. 消息结构(WeixinMessage)
入站消息核心字段:
{
"from_user_id": "o9cq800kum_xxx@im.wechat",
"to_user_id": "e06c1ceea05e@im.bot",
"message_type": 1,
"message_state": 2,
"context_token": "AARzJWAFAAABAAAAAAAp...",
"item_list": [
{ "type": 1, "text_item": { "text": "你好" } }
]
}
7.1 ID 格式规律
- 用户 ID:
xxx@im.wechat - Bot ID:
xxx@im.bot
7.2 常量表
| 字段 | 值 | 含义 |
|---|---|---|
message_type |
1 | 用户消息(入站) |
message_type |
2 | Bot 消息(出站) |
message_state |
2 | FINISH(完整消息) |
item.type |
1 | 文本(text_item.text) |
item.type |
2 | 图片(CDN 加密存储) |
item.type |
3 | 语音(silk 编码,voice_item.text 附 ASR 转写文字) |
item.type |
4 | 文件附件 |
item.type |
5 | 视频 |
媒体类 item 的详细字段(CDN 引用、aes_key 等)见 03-messages-and-media.md。
8. context_token:对话关联的核心
整个协议里最关键、最容易踩坑的细节:
- 每条入站消息都带
context_token,回复时必须原样带上,否则消息无法关联到正确的对话窗口 - 每条入站消息都应刷新本地保存的 token(Java SDK 的做法:
FileContextTokenStore按对话持久化,每条入站消息更新),这样主动发消息时也有最新 token 可用 - 有资料称:用户最后一条消息超过 24 小时后,bot 的消息可能送达不到;在窗口内可用
context_token主动追发消息。做定时推送类功能时必须考虑这个窗口(⚠️ 建议实测确认)
9. 输入中状态(typing)
POST /ilink/bot/getconfig → 获取 typing_ticket
POST /ilink/bot/sendtyping → 发送「正在输入」
用途:AI 后端处理耗时较长时,先发个 typing 让用户知道 bot 在干活。非必需,第一版可以不做。
10. 错误处理备忘
| 现象 | 含义 | 处理 |
|---|---|---|
errcode = -14 |
会话/token 过期 | 暂停轮询与发送,走重新扫码流程 |
ret != 0 |
业务错误 | 记录完整响应,按退避策略重试 |
| HTTP 层超时 | 长轮询正常超时或网络抖动 | 直接重试 |
| 重复收到同一条消息 | get_updates_buf 没更新/没持久化 |
检查游标保存逻辑;应用层按消息 ID 去重兜底 |
11. 协议层 Checklist(实现自查)
- 扫码登录:
get_bot_qrcode→ 渲染二维码 → 轮询get_qrcode_status到confirmed - 持久化:
bot_token/ilink_bot_id/ilink_user_id/baseurl/get_updates_buf/ 每对话context_token - 请求头:
Authorization、AuthorizationType、随机X-WECHAT-UIN - 长轮询循环:超时 > 服务端 timeout、游标即时保存、异常不中断
- 回复带
context_token、带唯一client_id - errcode=-14 的暂停与重新登录路径
- 退避重试策略