下载原文
8080 文档 · 插件基础版本 8.0.80 · 内容以文档原文为准

WeBridge 插件内置 HTTP 接口

本文档版次为 8080,沿用 8079 的业务接口约定;当前插件主版本为 8.0.80,本次构建为 8.0.80-2。用户已确认现有全部业务功能在微信 8.0.80 验证通过;下文保留旧版本的具体真机记录。新增的设置页检查更新仍需单独完成真机弹窗与浏览器下载联调。示例中的当前版本和构建标记用于说明格式,排错时以设备实际返回为准。

本文适用插件 8.0.80。调用方直接访问手机的 HTTP 服务;配置、鉴权、接口、事件、结果判断和排错均在本篇内。Apifox 是同一 HTTP 协议的可导入调试形式。

目录


1. 接口与接入准备

插件在你的 iPhone 上开了一个 HTTP 服务,默认监听 19088 端口、绑定所有网卡。你用任何能发 HTTP 请求的语言调用它,就能让微信发消息、查联系人、同意好友申请等。

项目 值
默认端口 19088(可在插件设置页修改)
监听地址 所有网卡(同一局域网内的设备都能访问)
协议 HTTP/1.1
请求体 JSON
响应体 JSON(Content-Type: application/json)
调用示例 http://192.168.0.100:19088/send_message

和"长轮询 / WebSocket"的关系:那个是插件主动连你的服务器;这个是你主动连插件。本地 HTTP 除了发送和查询,还可通过 POST /events 主动拉取微信事件。三者的事件队列独立,调用 /events 不会消费或改变长轮询、WebSocket 的事件。不同模式的选型对比可另看《接入总览与模式选择》,不影响按本文独立接入。

首次接入按以下顺序验证:先请求 GET /health 检查端口与 auth_authorized,确认微信登录及插件已启用,再向 filehelper 发送一条文本;需要接收事件时按第 4 节维护自己的游标。第 5 节可按业务查找入口。文中手机 IP、账号、消息 ID、资源地址和凭据示例均须替换为实际值。


2. 请求、鉴权与功能开关

这一节里的每一条都是插件实际强制的行为,写客户端前请务必看完。

2.1 长连接

插件不支持 HTTP keep-alive。 每一个响应都带 Connection: close,连接用完即断。你的 HTTP 客户端必须容忍这一点——不要依赖连接复用,也不要因为连接被关闭而误判为错误。

2.2 请求体大小

上限 1 MiB。 超过会返回 413:

{ "ok": false, "error": "请求体过大,最大允许 1 MiB" }

⚠️ 实践影响:图片、视频、语音、文件不要用 Base64 塞进请求体。这些接口设计上都是传路径或 URL,由插件自己去取。真要塞大文件,请改用"传 URL"的形式。

2.3 并发与超时

项目 值 说明
并发连接上限 32 同时处理的客户端连接数
请求接收超时 约 10 秒 超时返回 408
/events 等待请求上限 4 只限制正在等待新事件的请求,超过返回 429

普通微信业务调用默认串行,批量发消息时请自行控制节奏。创建群聊、直接加人和发送入群邀请使用独立的后台等待路径,等待回包只占用当前连接,不阻塞其他业务请求;同群操作仍由业务服务限制并发,详见群操作。其他长等待接口的并发方式以各自章节为准。

2.4 请求体必须合法

  • 必须是 UTF-8 编码的 JSON 对象。
  • body 解析失败或JSON不是对象时,插件会当作空参数继续走业务流程,不会独立返回JSON语法错误。多数旧接口表现为 400 加业务错误;创建群聊、直接加人和发送入群邀请返回 200 的完整参数失败结果。无论状态码如何,参数失败时都应先检查JSON是否合法。
  • 建议始终显式带上 Content-Type: application/json。

2.5 参数的类型转换很宽松

多数接口对参数类型做过兼容处理,这对你是好消息也是陷阱:

情况 行为
该传字符串、你传了数字 多数接口会自动转成字符串(例如 receiver: 12345 变成 "12345");/set_group_name 的 room_id、new_name 和 /get_group_notice 的 room_id 必须是字符串
该传数字、你传了数字字符串 会被解析成数字("100" → 100)
布尔字段 接受 1/0、true/false、yes/no、y/n(大小写不敏感);无法识别时用默认值
字符串参数 会自动去掉首尾空白与换行
该传数组、你传了单个值 部分参数会自动包装成单元素数组(不是所有参数都支持)

⚠️ 陷阱:因为转换宽松,类型写错不会报错,只会得到意想不到的结果。例如把数字 limit 写成 "abc" 会被当作 0,而不是报参数错误。

资料设置接口和资料预校验探针使用严格类型校验:sex 只接受整数 0/1/2,拒绝布尔值、小数(包括 1.0)、字符串和 null;文本必须是字符串。签名保持原始文本,拍一拍由微信原生规则处理空白,均不适用上面的通用字符串裁剪规则。

收藏三项接口同样严格校验参数,详见收藏用法,不适用上面的自动转换和裁剪规则。

2.6 方法严格匹配

每个端点的 HTTP 方法都是固定的。用错方法(例如对 GET /account_status 发 POST)会直接落进 404。

2.7 GET 接口的参数位置

GET 类接口(/health、/account_status、/debug/device_status 等)不接受任何查询参数,路径后面的 ?xxx=yyy 会被忽略。媒体读取的operation_id放在路径内,分段范围通过Range请求头传入。

2.8 鉴权

插件有一套授权检查。未授权时,除下列 7 个路径外,所有请求都会被拒绝(返回 403):

免鉴权路径
/
/health
/debug/bridge_status
/debug/keepalive_status
/debug/device_status
/device_status
/account_status

这意味着:你可以用 /health 判断插件是否在线,但未授权时几乎什么都做不了。 授权状态会在响应里以 auth_status 返回。

这里检查的是插件自身的授权资格,当前 HTTP 接口不校验调用方 API Key 或 Bearer Token;应通过可信网络限制谁能访问手机端口。

这里检查的是手机插件自身的授权状态;本地 HTTP 不校验调用方请求 Token,不要求添加 Authorization 请求头。已授权也仍需满足微信登录和对应业务条件。

2.9 功能开关

插件设置页里有若干开关,关闭后多数旧接口返回 400 和 <接口名> is disabled。创建群聊、直接加人和发送入群邀请的新请求返回 200、ok:false、error_code:WRITE_DISABLED;已登记同ID结果的读取先于该开关检查。旧接口示例:

{ "ok": false, "error": "send_message is disabled" }
开关 影响范围
插件总开关 默认关闭;有效启用还要求插件授权有效。发送、转发、接收回调和模拟状态均跟随它,没有独立设置入口;只读接口按各自说明处理
发送状态 所有"发送类"与"群组操作类"接口(实际等同总开关)
转发状态 转发类接口(实际等同总开关)
接收回调状态 跟随插件总开关;总开关关闭后不再生成新事件。已存在的 HTTP 缓冲与只读查询按各接口约定处理

本文各业务中提到的“发送/转发开关”表示底层有效状态,当前都跟随插件总开关;调用方如需分别控制发送与接收,应自行限制对应操作。

例外(不做开关检查的接口):/download_message_image、所有 /debug/* 探针、/livephoto_probe、/livephoto_diagnostics、/room_members、/get_group_notice、/get_chatroom_qrcode、/get_self_qrcode、/get_group_invitation、/friend_pay_name、/friends*、/groups_all 不受发送开关拦截。

后台保活另有独立设置,不改变上述业务接口开关:

保活设置 默认值 行为
后台保活 关闭 总开关;关闭即停止本插件音频、定位及后台检查,两个子开关保留选择并置灰
音频保活 开启 总开关开启后,允许在后台播放保活音频;前台停止,录音 / 通话中让出
持续定位保活 关闭 总开关开启后,从前台启动定位并延续到后台;需宿主声明、系统定位及权限满足条件
掉线提醒 关闭 控制本地掉线提醒,不提供额外后台执行能力

两种通道可单独或同时开启。audio_enabled/location_enabled 表示保存的选择,实际运行看 保活状态接口 的 enabled/active/audio_playing/location_updates_requested/location_active/timer_active;总开关关闭后子配置仍为 true 属于正常行为。查询该接口不会开启保活。


3. 返回结果与错误

所有 HTTP JSON 响应(包括成功和错误)都会带顶层 version 字段,当前为 "8.0.80-2"。下方业务示例省略这一公共字段;build_marker 用于区分同版本的不同构建,接入时保存设备实际返回值;示例中的历史构建标记不代表当前安装包。当前源码标记为 webridge_build_20261106_settings_update_8080。

3.1 状态码总表

状态码 含义 响应体
200 请求受理、查询结果,或明确保留完整业务结果的接口 必须判断ok/status;创建群聊、直接加人和发送入群邀请的参数错误、业务失败和写入关闭也返回200
206 媒体单段范围读取 文件二进制与Content-Range
416 媒体Range无效 Content-Range给出总长度
400 多数旧接口的参数错误/业务失败/功能关闭;不用于本篇群操作三项的业务结果 {"ok": false, "error": "<原因>"}
403 未授权 {"ok": false, "error": "authorization required", "auth_status": "<状态>"}
404 路径或方法不匹配 {"ok": false, "error": "route not found", "build_marker": "...", "method": "...", "path": "..."}
408 请求接收超时 {"ok": false, "error": "请求接收超时"}
413 请求体过大 {"ok": false, "error": "请求体过大,最大允许 1 MiB"}
429 同时等待的 /events 请求超过 4 个 {"ok": false, "error": "too_many_event_waiters", ...}

排错提示:404 的响应体里回显了你实际请求的 method 和 path。路径拼错时直接看这两个字段,比猜快得多。

3.2 传输成功、业务受理与最终完成

不要只看 HTTP 状态码,也不要只看 ok。

多项接口会在业务失败时保留完整结果并返回 HTTP 200;异步任务和发送操作还可能先返回“已受理”。因此先检查传输状态和 ok,再按该接口的 status、确认字段判断最终结果。

推荐的判断顺序:

  1. HTTP 状态码是 200
  2. 且响应体里 ok == true

好友支付姓名和群二维码查询会等待终态,分别检查 pay_name_status 和 status,详见支付姓名查询及群二维码查询。朋友圈等异步动作还必须等待终态;媒体上传需upload_completed=true,不能用首次ok=true判断完成。详见本篇朋友圈流程。

收藏发送的 accepted 仅表示本地链路受理;删除成功须 status:"deleted" 且 server_confirmed:true,详见收藏状态与重试。

3.3 error 字段

  • 成功时可能是空字符串 "",也可能不存在在响应里(取决于接口)。
  • 失败时是非空字符串,内容是原因描述。
  • 最外层的错误原因来自统一封装;个别接口失败时,响应体会直接采用业务层返回的完整结果对象(可能额外带 uploaded、message_id 等字段),此时 error 依然是字符串。

不要精确匹配 error 的文案做流程分支,它可能随版本调整。有 error_code 时优先按该接口的错误码处理;同时检查 HTTP 状态码、ok 和业务状态,把 error 留作日志。


4. 健康检查与事件接收

GET / 与 GET /health

两者完全等价,返回同一份内容。它们均免鉴权,适合作为连通性探针;其他免鉴权路径见第 2 节。

响应示例:

{
  "ok": true,
  "plugin": "webridge",
  "version": "8.0.80-2",
  "command_poll_url": "",
  "long_poll_interval_seconds": 20,
  "auth": {},
  "auth_authorized": true,
  "auth_status": "authorized",
  "bind_address": "0.0.0.0",
  "listen_port": 19088,
  "plugin_enabled": true,
  "receive_enabled": true,
  "send_enabled": true,
  "forward_enabled": true,
  "mock_enabled": true,
  "log_capture_enabled": true,
  "log_entry_count": 0,
  "build_marker": "webridge_build_20261106_settings_update_8080"
}
字段 类型 说明
ok bool 恒为 true(能返回就说明服务活着)
plugin string 固定为 webridge
version string 插件版本号
command_poll_url string 当前配置的长轮询服务端地址;空串表示没配
long_poll_interval_seconds int 当前轮询间隔(秒)
auth object 授权快照原始内容
auth_authorized bool 是否已授权
auth_status string 授权状态字符串
bind_address string 实际监听地址
listen_port int 实际监听端口
plugin_enabled bool 插件总开关
receive_enabled bool 接收回调开关
send_enabled bool 发送开关
forward_enabled bool 转发开关
mock_enabled bool 模拟模式开关
log_capture_enabled bool 日志采集开关
log_entry_count int 当前日志条数
http_event_queue_count int 当前 HTTP 事件缓冲区条数
event_spool_max_count int 当前最大暂存条数配置
event_spool_max_age_seconds int 当前最大暂存时间,0 表示不过期
build_marker string 构建标记

注意:/health 不会告诉你"长轮询/WebSocket 哪个在生效",只会给你 command_poll_url。判断传输模式请以插件设置页为准。

4.1 主动拉取微信事件

POST /events

供只使用插件本地 HTTP 接口的调用方主动拉取收到的微信消息、好友申请、群成员变化等事件。该接口始终可用,不参与“长轮询 / WebSocket”模式选择。

事件捕获后会复制一份到独立的 HTTP 事件缓冲区,同时继续走当前长轮询或 WebSocket 链路:

微信事件
  ├─ HTTP 事件缓冲区 -> POST /events 拉取
  └─ 当前传输模式
       ├─ 长轮询 -> POST /agent/event
       └─ WebSocket -> event 帧

调用 /events 不会删除长轮询或 WebSocket 队列中的消息,也不会影响发送、查询等其他 HTTP 接口。多个 HTTP 客户端各自保存自己的 offset,读取时互不抢占。

请求字段:

字段 类型 必填 默认值 说明
offset int64 — 0 下一条希望读取的 update_id;首次调用传 0
limit int — 50 单次最多返回条数,范围 1 ~ 100
timeout_seconds int — 20 没有事件时最多等待秒数,范围 0 ~ 25;0 表示立即返回

调用方自身的 HTTP 超时必须大于 timeout_seconds,建议至少多留 5 秒,例如请求等待 20 秒时把客户端超时设为 25 ~ 30 秒。

首次请求:

curl -X POST http://192.168.0.100:19088/events \
  -H "Content-Type: application/json" \
  -d '{"offset":0,"limit":50,"timeout_seconds":20}'

有事件时响应:

{
  "ok": true,
  "events": [
    {
      "update_id": 1780000000101,
      "device_id": "webridge_device_xxx",
      "session_id": "sess_xxx",
      "account_id": "wxid_self",
      "runtime_version": "8.0.80-2",
      "build_marker": "webridge_build_20261106_settings_update_8080",
      "ts_ms": 1780000000101,
      "event_name": "message",
      "event_id": "msg:7307587870543245070",
      "captured_at_ms": 1780000000090,
      "enqueued_at_ms": 1780000000100,
      "body": {
        "message_id": "7307587870543245070",
        "msg_type": "text",
        "chat_id": "wxid_friend",
        "room_id": "",
        "sender_id": "wxid_friend",
        "is_group": false,
        "content": "你好"
      }
    }
  ],
  "next_offset": 1780000000102,
  "earliest_offset": 1780000000101,
  "latest_offset": 1780000000101,
  "has_more": false
}

客户端应在整批事件处理成功后保存响应中的 next_offset,下一次原样回传:

curl -X POST http://192.168.0.100:19088/events \
  -H "Content-Type: application/json" \
  -d '{"offset":1780000000102,"limit":50,"timeout_seconds":20}'

如果暂时没有事件,请求会等待,事件到达后立即返回;等待到期仍没有事件时正常返回空数组:

{
  "ok": true,
  "events": [],
  "next_offset": 1780000000102,
  "earliest_offset": 1780000000101,
  "latest_offset": 1780000000101,
  "has_more": false
}

收到空数组不是错误。客户端应立即使用相同 offset 发起下一轮请求。

消费语义:

  • 接口提供至少一次(at-least-once)读取语义,不承诺 exactly-once。
  • 客户端处理成功后才保存 next_offset;处理中途失败时继续使用旧 offset,事件会再次返回。
  • 调用方应按 event_id 做业务去重。
  • limit 只限制单次响应条数;has_more: true 时应使用 next_offset 立即继续拉取。
  • /events 本身不删除消息;事件只会因最大条数、最大暂存时间或用户手动清空而淘汰。

offset 已过期:

HTTP 事件缓冲区复用设置页的“最大暂存条数”和“最大暂存时间”。请求位置已经被淘汰、进程重启导致旧事件消失,或者设置页手动清空后,接口返回 HTTP 200 和:

{
  "ok": false,
  "error": "offset_expired",
  "message": "请求位置已超出当前事件保留范围,请从 next_offset 重新拉取",
  "requested_offset": 1780000000001,
  "earliest_offset": 1780000000101,
  "latest_offset": 1780000000120,
  "next_offset": 1780000000101,
  "events": [],
  "has_more": false
}

这表示中间可能有事件已丢失。调用方应记录告警,再根据业务选择从 next_offset 继续,不能把它当成普通空队列静默忽略。恢复方式见 4.2。

暂存设置:

  • 默认最多保留 500 条,硬上限 5000 条。
  • 默认最长保留 2 分钟,设置为 0 表示不过期。
  • “断线后启用暂存”只控制长轮询和 WebSocket 的失败补发,关闭它不会关闭 HTTP 事件缓冲区。
  • 设置页分别显示“当前传输暂存”和“HTTP 事件暂存”。
  • “一键清空暂存”会清理当前传输队列和 HTTP 事件缓冲区,不会清理当前未启用的另一种传输队列。

4.2 游标、分页与客户端循环

offset 是本次希望读取的起始位置,不会删除服务端事件。首次传 0,之后只使用响应中的 next_offset;正常响应须在整批处理成功后再保存,网络异常和业务处理失败时保留原游标,重读后按完整 event_id 去重。

4.2.1 事件解析

每种事件的完整 body 定义见 4.3。不要把红包、转账或好友申请套入普通 message 字段。还需注意:

  • 本机发出的消息也可能入队,结合 sender_id 和事件信封的 account_id 判断方向。
  • 消息 ID 按字符串保存,不假设固定长度;文件和链接属于 msg_type=app,由 msg_subtype 区分。
  • 图片事件提供媒体引用,不包含可由电脑直接读取的图片文件;获取文件使用 媒体接口。
  • is_at 与 at_user_list 的含义不同,按事件字段说明处理;去重须比较完整 event_id,不能只取其数字后缀。

4.2.2 当前游标和分页规则

字段/场景 当前行为
earliest_offset 目前最早保留的事件编号;缓冲为空时为下一个待分配编号
latest_offset 有保留事件时为最后一条编号;缓冲为空时保留本进程最后分配的编号,从未入队时才为 0
next_offset 有返回事件时为本批最后一条 update_id + 1;空批次保留本次有效起点,首次 offset=0 时使用 earliest_offset
has_more 本批之后仍有已入队事件时为 true;它不是“此后永远不会有新事件”的标志
分页 最多返回 limit 条。积压超过一页时,按 next_offset 续拉,不能直接跳到 latest_offset + 1
位置超界 非零 offset 小于最早保留位置,或大于当前下一个待分配编号时,返回 offset_expired
手动清空/自然淘汰 事件会消失;本进程的编号继续递增,不因清空自动重新编号
微信进程重启 缓冲消失,编号从新的时间基址开始;旧游标可能失效,按明确的 offset_expired 响应恢复

空批次与 has_more:false 均正常;处理完后立即开始下一轮。has_more:true 时已有积压可继续读取,下一次也可以仍带原等待参数:已有事件时不会等待。

4.2.3 游标过期和连接异常

  • 只有 HTTP 200、ok:false 且 error=offset_expired 时,才记录可能丢失事件的告警,并按响应的 next_offset 恢复。继续用旧游标会反复收到同一错误。
  • 响应不提供丢失条数,不能用游标差或 latest_offset-earliest_offset+1 计算准确丢失量或队列长度;重启、空缓冲和淘汰都会影响这些数值。
  • HTTP 400/403/429、其他 ok:false、网络超时或响应缺少合法 next_offset 时,不推进游标;分别修正参数、处理授权、减少等待并发或退避重试。
  • /health.http_event_queue_count 是另一次状态快照,不能替代本批返回的事件和游标。
  • 正常响应会关闭连接;等待中提前断线按瞬时网络异常处理,保留游标重试。客户端超时须大于 timeout_seconds,建议多留 5~10 秒。

历史 0.8.76 联调曾观察到少量事件下 has_more 始终为 false,这不能证明当前实现固定返回 false。上述规则按当前事件存储实现核对;本次文档整理未重新进行真机联调。

4.2.4 客户端循环

单个客户端串行拉取;正在等待新事件的请求全局最多 4 个。UTF-8 解析响应,整批处理成功后持久化 next_offset。Windows 排错时可先保存响应原文再按 UTF-8 查看,避免把终端编码问题当成接口内容错误。

offset = 0 或本客户端上次保存的 next_offset
循环:
    resp = POST /events {offset, limit, timeout_seconds}
    若网络异常或 HTTP 非 200:
        保留 offset;按状态处理授权、参数或限流,必要时退避重试
    否则若 resp.ok == true:
        校验 events 和 next_offset
        按 event_id 去重并处理整批事件
        整批成功后保存 offset = resp.next_offset
    否则若 resp.error == "offset_expired" 且 next_offset 合法:
        告警:保留范围外的事件可能已丢失,响应不提供丢失条数
        保存 offset = resp.next_offset
    否则:
        保留 offset,记录错误并处理原因,不静默跳过事件

4.3 完整事件类型与 body 字段

以下示例仅展示 /events 响应中 events[] 的 event_name、event_id 和 body 部分;update_id、账号/设备标识及时间戳仍按4.1读取。消息方向结合 sender_id 与事件信封的 account_id 判断,本机发送的消息也可能入队。本节包含纯 HTTP 接入所需的全部事件定义,无需查阅 WebSocket 或长轮询文档。

4.3.1 事件类型总表

event_name 说明
moments_result 本次接口/命令对应的朋友圈页面或写入结果;含 operation_id/request_id/status/revision,见 本篇朋友圈完整用法
message 普通聊天消息(文本、图片、语音、视频、表情、文件、链接、拍一拍、系统消息等)
red_packet_received 收到红包
transfer_received 收到转账
transfer_refund_result 转账退还结果:成功、失败或未知,按 native_status 判断
group_member_join 群成员加入
group_member_leave 群成员离开
group_member_nickname_change 群成员修改或清除群内昵称
friend_request 收到好友申请

4.3.2 message 事件

{
  "event_name": "message",
  "event_id": "msg:7307587870543245070",
  "body": {
    "message_id": "7307587870543245070",
    "msg_type": "text",
    "raw_message_type": 1,
    "chat_id": "50136399923@chatroom",
    "room_id": "50136399923@chatroom",
    "sender_id": "wxid_member",
    "is_group": true,
    "is_at": false,
    "at_user_list": [],
    "at_all": false,
    "create_time": 1774772029,
    "content": "你好"
  }
}
恒有字段(一定会出现)
字段 类型 说明
message_id string 消息 ID。取不到服务端消息 ID 时会退化为毫秒时间戳字符串
msg_type string 插件映射的消息类型,见下表;可能为 unknown
raw_message_type int 微信原生消息类型数字,见下表
content string 消息内容。对文本是文字,对图片/文件等是原始 XML 串,也可能是空串 ""
chat_id string 会话 ID(群聊为群 ID,私聊为对方或自己 wxid)。可能为空串
room_id string 群 ID;私聊时为空串 ""(字段仍在)
sender_id string 发送者 wxid
is_group bool 是否群聊
is_at bool 是否 @ 了当前账号本人;私聊恒为 false
at_user_list string[] 被 @ 的 wxid 列表;无 @ 或私聊时为空数组 []
at_all bool 是否 @ 所有人
create_time int 微信消息时间,单位:秒(注意与 ts_ms 的毫秒不同)
消息类型对照
msg_type raw_message_type 说明
text 1 文本
image 3 图片
voice 34 语音
video 43 视频
contact_card 42 名片
emoji 47 表情
app 49 App 消息(链接、文件、小程序、合并转发、引用等都在这一类)
pat 0 拍一拍
system 10000 系统消息(撤回、群名修改等)
unknown 其他 未能识别的类型

⚠️ 注意一个真实差异:代码里的 msg_type 实际取值包含 contact_card 和 app,没有 file 和 link。文件和链接是 app 类型下的子分类,靠 msg_subtype 区分。请不要按 msg_type == "file" 来判断文件消息。

条件字段(只在满足条件时出现,不满足则整个字段不存在)
出现条件 字段 类型 说明
content 能被识别为 XML content_xml string 归一化后的完整 XML
同上 content_prefix string XML 之前的非空文本前缀
msg_type == image image_md5、image_aes_key、image_thumb_url、image_mid_url、image_origin_md5 string 图片解密与多档清晰度地址——下载图片需要 image_aes_key
同上 image_length int 字节
msg_type == voice voice_url、voice_aes_key、voice_md5、voice_from_user、voice_client_msg_id string 语音下载信息
同上 voice_length_ms int 毫秒
同上 voice_data_length int 字节
msg_type == emoji emoji_md5、emoji_aes_key、emoji_cdn_url、emoji_encrypt_url string
同上 emoji_length、emoji_width、emoji_height int 字节 / 像素
msg_type == contact_card card_username、card_nickname、card_alias、card_province、card_city、card_sign、card_big_head_img_url、card_small_head_img_url string
同上 card_sex、card_scene int
msg_type == app app_msg_type int App 消息的内层类型:5 链接、6 文件、8 上传、19 合并转发、33 小程序、57 引用,其他为未知
同上 msg_subtype string 对应的可读名:link / file / upload / merged_records / mini_program / quote / app_unknown
同上 app_msg_title、app_msg_desc、app_msg_url、app_source_username、app_source_display_name、app_thumb_url、app_thumb_md5、app_aes_key string
msg_subtype == quote quote_msg_id、quote_from_user、quote_chat_user、quote_display_name、quote_content string 引用消息的原文信息
同上 quote_msg_type、quote_create_time int 引用消息的类型与时间
拍一拍专属 pat_from_user、pat_patted_user、pat_template string 见本篇拍一拍事件

⚠️ 判断文件消息的正确方式:msg_type == "app" 且 msg_subtype == "file"。

被主动剥掉的字段(不会出现在 body 里)

from_user、to_user、sender_id_type、real_chat_user、source、hook_selector、hook_type、self_user、以及内部的 msg_id(已被改名为 message_id)。

这意味着服务端拿不到"这条消息是发给谁的"直接的收发方向字段,只能靠 chat_id / room_id / sender_id / is_group 自己推断方向。这是设计如此,不是 bug。

群内 @ 字段的精确语义
字段 说明
is_at 本条消息是否 @ 了当前登录账号本人
at_user_list 本条消息里所有被 @ 的 wxid。取自微信消息自带的 @ 名单,插件只做去空白和去重,不做昵称解析
at_all 是否 @ 了所有人;等价于 at_user_list 中含协议标记 notify@all

三条必须知道的约定:

  1. @所有人 时微信写入的是协议标记 notify@all 而不是 wxid,插件按原样透出并同时给出 at_all: true,不会展开成全部群成员(消息时刻的成员列表无法还原,展开会失真)
  2. is_at 与 at_user_list 相互独立:is_at 以微信自身判断为准,at_user_list 是消息里的原始名单。@所有人 或消息未携带相关数据时,可能出现 is_at: true 而 at_user_list 为空
  3. 群消息中 chat_id 与 room_id 相同且 is_group 为 true;私聊中 room_id 为空串、is_group 为 false

4.3.3 拍一拍

msg_type 为 pat,走系统消息通道,raw_message_type 为 0:

{
  "event_name": "message",
  "event_id": "msg:7307587870543245070",
  "body": {
    "message_id": "7307587870543245070",
    "msg_type": "pat",
    "raw_message_type": 0,
    "chat_id": "wxid_friend",
    "room_id": "",
    "sender_id": "wxid_friend",
    "is_group": false,
    "create_time": 1774772029,
    "content": "你拍了拍自己",
    "pat_from_user": "wxid_friend",
    "pat_patted_user": "wxid_self",
    "pat_template": "你拍了拍自己"
  }
}
字段 说明
pat_from_user 拍的人的 wxid
pat_patted_user 被拍的人的 wxid
pat_template 原始模板文本(如"你拍了拍xxx")

注意两个字段的区别:content 是把 ${wxid} 占位符替换成显示名之后的文案(给人看的);pat_template 是未解析的原始模板。要展示请用 content。

4.3.4 红包事件

{
  "event_name": "red_packet_received",
  "event_id": "red_packet:rp_msg_7307587870543245070",
  "body": {
    "red_packet_id": "rp_msg_7307587870543245070",
    "message_id": "7307587870543245070",
    "chat_id": "50136399923@chatroom",
    "room_id": "50136399923@chatroom",
    "sender_id": "wxid_sender",
    "from_user": "wxid_sender",
    "to_user": "wxid_self",
    "create_time": 1774772029,
    "raw_message_type": 49,
    "send_id": "1000039501202603311234567890",
    "channel_id": "1",
    "msg_type": "1",
    "native_url": "…",
    "sign": "",
    "scene_id": 1002,
    "session_user_name": "…",
    "nick_name": "…",
    "head_img": "",
    "is_group": true,
    "is_openim": false,
    "is_group_sender": false,
    "in_way": "0",
    "timing_identifier": "",
    "status": "received",
    "created_at_ms": 1774772029000,
    "updated_at_ms": 1774772029000
  }
}
字段 说明
red_packet_id 领取红包时唯一需要回传的参数(receive_red_packet / red_packet_detail)。去重请用它
send_id、channel_id、native_url 红包领取链路必需。这三者任取不到时,整个事件不会生成
timing_identifier 事件发出时恒为空串 ""(领取流程中才回填)
status 事件发出时恒为 "received"。后续领取状态只更新本地缓存,不会重新上报成事件
msg_type ⚠️ 语义冲突:这里不是微信消息类型名,而是红包链路的 msgtype 查询参数(空则 "1")。别和 message 事件的 msg_type 混用
created_at_ms / updated_at_ms 毫秒(注意 create_time 是秒)
nick_name / head_img 发红包的人的昵称与头像
session_user_name 群内自己发时为 to_user,否则为 from_user

⚠️ 红包事件 body 里没有 content / content_xml,也没有 app_msg_* 系列字段——它是独立构造的,不复用消息字段。

4.3.5 转账事件

{
  "event_name": "transfer_received",
  "event_id": "transfer:1000050001202604140530193566598",
  "body": {
    "transfer_id": "1000050001202604140530193566598",
    "message_id": "8871556727500760296",
    "chat_id": "wxid_demo_account",
    "room_id": "",
    "sender_id": "wxid_demo_account",
    "from_user": "wxid_demo_account",
    "to_user": "wxid_demo_friend",
    "real_chat_user": "wxid_demo_account",
    "current_user": "wxid_demo_friend",
    "receiver_username": "wxid_demo_friend",
    "payer_username": "",
    "control_transaction_id": "53010002669213202604143932510122",
    "amount_text": "¥0.02",
    "amount_value": "0.02",
    "amount_fen": 2,
    "memo": "",
    "remark": "",
    "nickname": "…",
    "app_msg_type": 2000,
    "app_msg_title": "微信转账",
    "app_msg_desc": "",
    "app_msg_url": "",
    "msg_subtype": "…",
    "content": "",
    "content_xml": "<msg>...</msg>",
    "native_url": "",
    "create_time": 1774772029,
    "raw_message_type": 49,
    "status": "received",
    "created_at_ms": 1774772029000,
    "updated_at_ms": 1774772029000,
    "pay_info_class": "…",
    "pay_info_probe": {}
  }
}

金额字段说明(三个都有,别搞混):

字段 类型 说明
amount_text string 带符号的展示文本,如 "¥0.02"
amount_value string 字符串形式的元值,如 "0.02"
amount_fen int 整数分,如 2 → 推荐用它做金额计算,避免浮点误差

身份字段说明(六个高度重叠,按需取用):

字段 含义
sender_id 消息发送者
from_user 转账付款方
to_user 转账收款方
receiver_username 收款方用户名
payer_username 付款方用户名(可能为空串)
current_user 历史接收方上下文字段,不是独立登录凭证;不要据此覆盖原生付款方/收款方参数

建议至少持久化:transfer_id、message_id、control_transaction_id、amount_text、amount_fen、sender_id、chat_id。 推荐用 transfer_id 去重。

注意:

事项 说明
status 首次解析通常为 "received",这里只表示收到了转账消息,不代表资金已收取;同笔上下文重读时可保留已有状态。资金状态请用 get_transfer_status 的 native_status 判断;退还结果另有独立事件
create_time 秒;取不到时为 0(不是当前时间)
app_msg_type / msg_subtype 可能是 JSON null,解析时要容忍
room_id 有,但没有 is_group 字段(与 message 事件不同)
content_xml 原始 XML,字段很长,不需要的话别存
防误报 如果这条消息被识别成红包证据,插件不会生成转账事件

转账退还结果事件 transfer_refund_result

本事件沿本模式标准事件外壳传输。HTTP 通过 /events 拉取;WebSocket 使用 event 帧;长轮询上报到 /agent/event。下面展示本节相关字段,公共时刻、设备、账号与队列字段按本模式事件约定携带:

{
  "event_name": "transfer_refund_result",
  "event_id": "transfer_refund:refund_result_example",
  "body": {
    "ok": true,
    "transfer_id": "transfer_example",
    "message_id": "message_example",
    "accepted": true,
    "confirmed": true,
    "status": "refunded",
    "native_status": 2002,
    "ret_code": 0,
    "error_code": "",
    "error": "",
    "refund_result_id": "refund_result_example",
    "source": "webridge_live"
  }
}

body 保留退还业务结果的全部基础字段:ok、transfer_id、message_id、accepted、confirmed、status、native_status、ret_code、error_code、error,另有非空 string refund_result_id(本次结果事件的独立标识)及 string source(来源诊断字段,不用于业务判断)。微信错误回包还可能带 wx_error_type(integer 或 null)。字段类型、所有状态与错误码见本文 转账退还与查询。event_id 为 transfer_refund:<refund_result_id>,消费时按完整 event_id 去重,不按 transfer_id 去重,以免把查询或后续结果吞掉。

事件名不代表成功:只有 native_status=2002 且 status="refunded" 才确认已退还。已进入退还提交且操作结束时才可能产生事件,可能是成功、失败或 refund_unknown;仅返回 refund_pending 时还未结束,后续回包或主动查询查到终态可能完成原动作并产生事件。在 refund_unknown/failed 等已结束动作之后再查询,只保证返回状态和回收占用,不保证补发第二个退款结果事件。 未提交就被拒绝、预检发现已经退还均不发此事件;账号会话变化后的旧结果不投递给新账号。因此客户端必须保留主动查询路径,不能只等事件。

4.3.6 群成员变更事件

{
  "event_name": "group_member_join",
  "event_id": "msg:group_member_join:50136399923@chatroom:wxid_member:1775000001123",
  "body": {
    "room_id": "50136399923@chatroom",
    "member_id": "wxid_member",
    "member_nick_name": "张三",
    "member_remark": "",
    "member_alias": "",
    "member_display_name": "张三",
    "room_nick_name": "项目群",
    "room_remark": "",
    "message_id": "group_member_join:50136399923@chatroom:wxid_member:1775000001123",
    "snapshot_before_count": 23,
    "snapshot_after_count": 24,
    "create_time": 1775000001,
    "is_group": true
  }
}

group_member_leave 使用相同的群/成员字段,表示成员离开;snapshot_before_count、snapshot_after_count 分别为变更前后成员数。

昵称变更事件额外带:

{
  "event_name": "group_member_nickname_change",
  "body": {
    "old_room_nick_name": "lumen",
    "new_room_nick_name": "lumen123",
    "snapshot_before_count": 23,
    "snapshot_after_count": 23
  }
}

注意:

事项 说明
群成员事件没有 msg_type / raw_message_type / sender_id / chat_id 它们被主动剥掉了,请用 room_id + member_id
create_time 秒
snapshot_before_count / snapshot_after_count 加入/离开事件里是群成员数;昵称变更事件里是昵称快照的条目数。⚠️ 同一字段名两种语义,别跨事件类型复用判断逻辑
首次建群快照不会产生 group_member_join 插件第一次看到某个群时不报加入
首次建立昵称快照不会产生 group_member_nickname_change 只有后续修改/清除才上报
退群事件有短暂确认延迟 避免同步抖动误报
昵称变更的确认机制 会按 150ms / 500ms / 1500ms 三次延迟复查确认,所以事件到达会略有延迟,且 member_display_name 等字段是复查后的值

4.3.7 好友申请事件

event_name 为 friend_request。

这个事件的 body 结构有明显的不确定性:event_id 会按以下优先级生成,说明至少存在三种数据形态:

  1. 有申请 ID → friend_request:<申请ID>
  2. 否则有消息 ID → msg:<消息ID>
  3. 都取不到 → 兜底 evt:<毫秒>

恒有字段:

字段 类型 说明
message_id string 消息 ID(可能是兜底的时间戳字符串)
msg_type string 固定 "friend_request"
content string 可能为空串
room_id string 强制为空串 ""
is_group bool 强制为 false
source_xml string 归一化后的完整 XML
create_time / is_at / at_user_list / at_all — 继承自消息基础字段

条件字段(取不到则不出现):

字段 说明
request_id 好友申请业务 ID
encrypt_username 加密用户名,同意申请时必须
ticket 凭证,同意申请时必须
scene 场景值
from_user / sender_id / chat_id 仅当解析出申请方用户名时才写入这三个键
nick_name、alias、sex、country、province、city、signature、big_head_img_url、small_head_img_url 申请方资料,按可取到的填

⚠️ 同意好友申请前请先校验 encrypt_username 和 ticket 是否都存在,缺失时不要盲调 accept_friend_request。

识别条件:只有满足特定特征的消息才会成为 friend_request 事件,否则会退回普通 message 事件。所以不要假设每个好友申请都一定会以 friend_request 出现。

4.3.8 HTTP 拉取的可靠性

HTTP 事件缓冲区独立、有界且只在当前进程内保留;不套用远程事件的磁盘补发规则。所有事件按完整 event_id 去重,同一客户端串行拉取,全部处理成功后再保存 next_offset;游标过期按 offset_expired 恢复,具体容量、TTL、等待和恢复流程见本篇第 4 节。不要根据游标数值差推算精确丢失条数。


5. 完整端点索引

按业务查找入口;完整参数、成功判断和重试边界见对应章节。通用诊断列表见第 18 节,旧路径与已移除入口见第 19 节。

5.1 健康与事件

方法 路径 用途
GET /、/health 健康检查与配置总览
POST /events 按 offset 主动拉取微信事件

5.2 消息发送与操作

方法 路径 用途
POST /send_message 发送文本(支持 @ / 引用 / @所有人)
POST /send_image 发送图片
POST /send_emoji 发送表情
POST /send_voice 发送语音
POST /send_video 发送视频
POST /send_video_from_url 发送视频(URL)
POST /send_livephoto 发送实况照片
POST /send_file 发送文件
POST /send_file_from_url 发送文件(URL)
POST /send_link_card 发送链接卡片
POST /send_music_card 发送音乐卡片
POST /send_contact_card 发送联系人原生名片
POST /send_location 发送单次位置,支持坐标反查补全文字
POST /send_xml 发送原始 appmsg XML
POST /send_signal 发送小信号
POST /send_pat 发送拍一拍
POST /forward_message 转发消息
POST /revoke_message 撤回消息

5.3 媒体

方法 路径 用途
POST /download_message_media 准备消息媒体并返回手机副本,见媒体完整说明
POST /upload_message_media 准备媒体并上传后端,见媒体完整说明
POST /upload_file_to_wechat_cdn 上传普通文件到微信 CDN,见媒体完整说明

5.4 好友与联系人

方法 路径 用途
POST /set_friend_remark 设置/清空好友备注,见好友设置
POST /set_friend_star 设置/取消好友星标,见好友设置
POST /set_friend_blacklist 加入/移出好友黑名单,见好友设置
POST /friends 好友列表(分页)
POST /friends_all 全部好友
POST /friend_pay_name 阻塞查询好友或群成员支付姓名末字,单次返回终态
POST /search_contact 搜索普通个人联系人,返回短期引用
POST /add_friend 搜索结果主动添加好友或发送验证申请
POST /add_room_friend 按共同群和成员 wxid 添加好友
POST /accept_friend_request 同意好友申请
POST /delete_friend 删除好友

5.5 群聊

方法 路径 用途
POST /groups_all 全部群聊
POST /room_members 群成员列表
POST /get_group_notice 读取本机缓存的群公告
POST /get_chatroom_qrcode 阻塞获取群二维码,返回本次 URL/可选图片与原始限制
POST /group_admin_operate 添加/移除群管理员、转让群主,见完整说明
POST /set_group_msg_silence 设置当前账号的群免打扰
POST /get_group_invitation 查询普通私聊入群邀请,仅需 message_id
POST /accept_group_invitation 纯协议接受邀请,仅需 message_id
POST /quit_group 退出群聊
POST /create_group 创建普通群聊
POST /add_group_member 直接添加群成员
POST /invite_group_member 发送入群邀请
POST /kick_group_member 踢出群成员
POST /set_group_self_nickname(别名 /rename_group、/set_group_nickname) 修改我在本群的群昵称(不是群名称)
POST /set_group_name 修改整个群聊的名称

5.6 会话、红包与转账

方法 路径 用途
POST /delete_session 删除会话
POST /receive_red_packet 领取红包
POST /red_packet_detail 红包详情
POST /receive_transfer 确认收款
POST /refund_transfer 退还待收取转账
POST /get_transfer_status 查询转账资金状态,不执行收款或退还

5.7 账号资料与个人二维码

方法 路径 用途
POST /get_self_qrcode 获取当前登录账号二维码 URL 与可选 PNG
POST /clear_gender_region 清除性别地区
POST /profile/update 批量设置或清空性别、地区、签名
POST /profile/gender 设置或清空性别
POST /profile/region 设置或清空地区
POST /profile/signature 设置或清空个性签名
POST /profile/pat_suffix 设置或清空拍一拍后缀,异步查询结果
POST /profile/region_codes 逐级查询国家、省、市地区代码
POST /profile_nickname 修改账号昵称

5.8 朋友圈

方法 路径 用途
POST /moments/list 好友最新时间线与历史
POST /moments/user 指定用户相册与可见期限
POST /moments/detail 联网获取动态详情
POST /moments/refresh 服务端触发刷新并接收结果
POST /moments/like 点赞
POST /moments/unlike 取消本人点赞
POST /moments/comment 评论与回复他人评论
POST /moments/delete_comment 删除评论
POST /moments/publish 发布文字、图文或视频
POST /moments/delete 删除本人动态
POST /moments/permissions/query 查询好友、期限、单帖权限
POST /moments/permissions/update 修改好友、期限、单帖权限
POST /moments/operation 查询原异步操作
POST /moments/media/download 准备媒体并可主动上传
GET /moments/media/file/{operation_id} 本地模式读取已准备媒体

5.9 收藏

方法 路径 用途
POST /favorites/list 收藏列表,最新在前的游标分页
POST /favorites/send 发送指定收藏到好友或群,本地受理返回 accepted
POST /favorites/delete 删除指定收藏,等待服务器确认

5.10 公众号

方法 路径 用途
POST /official_account_search 联网搜索公众号首批候选
POST /official_accounts 已关注公众号本地分页列表
POST /official_account_follow 关注公众号,单次等待结果
POST /official_account_unfollow 取消关注公众号,可能清理本地会话与消息
POST /official_account_articles 按 limit 自动翻页合并历史文章,用游标续取

5.11 状态与专题诊断

方法 路径 用途
POST /debug/location_geocode_probe 执行坐标反查,不发送消息
POST /debug/message_media_probe 查询媒体或已有 CDN 任务状态
POST /debug/group_invitation_probe 入群邀请 context/auth/info 只读探针
GET /account_status 账号状态
GET /device_status 设备状态
GET /debug/bridge_status 插件诊断快照
GET /debug/keepalive_status 保活状态与内存专用快照
POST /debug/moments_probe 运行能力与视频准备诊断

6. 消息发送

以下接口共用同一个接收方参数:receiver。

receiver 的取值:

场景 填什么
私聊 对方的 wxid,或你的好友备注名
群聊 群 ID(形如 1234567890@chatroom)
系统会话 filehelper(文件传输助手)——测试首选,不会打扰任何人

部分接口为了兼容旧调用方,还接受 toUser、to、chatId、target 等别名。新接入请统一用 receiver,别用别名。


POST /send_message

用途:发送文本消息,支持 @、@所有人、引用、引用并 @。

请求字段:

字段 类型 必填 说明
receiver string ✅ 接收方
content string ✅ 消息正文
quote_message_id string — 引用某条消息,填那条消息的 message_id
mention_user_list string[] — 要 @ 的 wxid 列表

mention_user_list 的别名(历史兼容,新接入请只用 mention_user_list):还接受 at_user_list;此外 at_user(单个 wxid)会被并入 @ 名单最前面。

发送模式自动推导(你不需要传 mode):

你传了什么 效果
只有 content 普通文本
mention_user_list @ 消息
quote_message_id 引用回复
两个都传 引用并 @

正文内联 @:

  • content 里可以用 {{mention:wxid}} 占位符,在正文任意位置插入 @。
  • 插件会自动把占位符渲染成 @显示名,并同步写入消息的 @ 名单。
  • 即使你不传 mention_user_list,只要正文里出现了 {{mention:wxid}},插件也会自动提取并走 @ 链路。
  • ⚠️ 如果占位符里的 wxid 解析不出备注名或昵称,整条消息会被拒绝发送(避免正文里直接出现原始 wxid)。

@所有人:

  • 仅群聊可用:把 mention_user_list 设为 ["notify@all"]。
  • notify@all 是微信的 @所有人协议标记,不是用户 wxid,不要展开成全部群成员。
  • mention_user_list 负责触发通知,content 里的 @所有人 只负责正文展示。
  • 插件不会自动往 content 里补 @所有人。要在聊天界面看到这四个字,必须你自己写进 content。
  • 是否允许发送仍受微信群主/管理员权限限制,插件不绕过微信的权限校验。

示例:

curl -X POST http://192.168.0.100:19088/send_message \
  -H "Content-Type: application/json" \
  -d '{
    "receiver": "50136399923@chatroom",
    "quote_message_id": "5611615190048272387",
    "mention_user_list": ["wxid_demo_account", "wxid_3c5980ggo5se22"],
    "content": "我现在{{mention:wxid_demo_account}},然后我还想在这里{{mention:wxid_3c5980ggo5se22}}。"
  }'

成功响应:

{
  "ok": true,
  "receiver": "50136399923@chatroom",
  "quote_message_id": "5611615190048272387",
  "mention_user_list": ["wxid_demo_account", "wxid_3c5980ggo5se22"]
}
字段 说明
ok 恒为 true
receiver 回显接收方
quote_message_id 仅当你传了才出现
mention_user_list 仅当有 @ 时才出现

失败响应:400 + {"ok": false, "error": "<原因>"}。常见原因:接收方为空、内容为空、wxid 无法解析、发送开关关闭。


POST /send_image

用途:发送图片。

请求字段:

字段 类型 必填 说明
receiver string ✅ 接收方
image_path string ✅ 本地绝对路径或远程 URL

成功响应:

{
  "ok": true,
  "resolved_image_path": "/var/mobile/.../photo.jpg",
  "receiver": "wxid_friend",
  "downloaded": false
}
字段 说明
resolved_image_path 插件最终实际使用的文件路径
downloaded 是否是从远程 URL 下载下来的

前置条件:发送开关必须开启,否则 400 "send_image is disabled"。


POST /send_emoji

用途:发送表情(gif / png / jpg / jpeg 均可)。

大小限制读取当前微信动态配置,实际值见/debug/emoji_send_probe的limits.max_file_size/max_dimension。字节上限为两种原生配置较大值与20MiB保护上限的较小值;静态默认5MiB不能替代真机配置。转换前和读取数据后均检查,超限明确报错,不提交发送。

请求字段:

字段 类型 必填 说明
receiver string ✅ 接收方
source string ✅ 本地路径或远程 URL(推荐用这个字段名)
emoji_path string — source 的兼容别名

说明:

  • 远程图片会自动下载到插件沙盒,缓存 1 天后自动清理。
  • 不是 gif 的图片会被转换成微信表情格式。

成功响应:

{
  "ok": true,
  "receiver": "wxid_friend",
  "source": "https://example.com/demo.png",
  "source_type": "remote_url",
  "emoji_path": "/var/mobile/.../demo.gif",
  "resolved_emoji_path": "/var/mobile/.../demo.gif",
  "downloaded": true,
  "emoji_md5": "…",
  "message_type": 47,
  "message_type_name": "emoji"
}

POST /send_voice

用途:发送语音。

请求字段:

字段 类型 必填 说明
receiver string ✅ 接收方
source string ✅ 本地路径或远程 URL(推荐用这个字段名)
duration_ms int — 语音时长(毫秒)

别名(这些字段名插件都认,但新接入请统一用上面的):

主字段 兼容别名
source voice_url、voice_path、audio_url、audio_path、video_url、video_path、aud_url、aud_path
duration_ms voice_length_ms、voice_duration_ms

说明:

  • 如果 source 本身就是 .aud 格式(微信语音格式),直接发送。
  • 否则插件会自动提取音频、转 PCM、编码成 SILK .aud 再发。这个过程有耗时,请把客户端超时设宽一些。
  • MP3、视频链接都能走这条路。

成功响应:

{
  "ok": true,
  "receiver": "wxid_friend",
  "source": "https://example.com/audio.mp3",
  "source_type": "remote_url",
  "resolved_local_path": "/var/mobile/.../audio.mp3",
  "resolved_pcm_path": "/var/mobile/.../audio.pcm",
  "resolved_wechat_aud_path": "/var/mobile/.../audio.aud",
  "duration_ms": 3240,
  "downloaded": true,
  "message_type": 34,
  "message_type_name": "voice"
}

POST /send_video

用途:发送视频。

请求字段:

字段 类型 必填 说明
receiver string ✅ 接收方
source string ✅ 本地路径或远程 URL
max_size_mb number — 大小上限(MB)。优先级高于 max_size_bytes
max_size_bytes int — 大小上限(字节)

默认上限:两个都不传时,默认 10 MiB(10485760 字节)。

别名:source 也接受 video_url、video_path。

说明:远程 URL 会先做大小探测,超限直接失败,不会白下载。

成功响应:

{
  "ok": true,
  "source": "https://example.com/test.mp4",
  "source_type": "remote_url",
  "resolved_video_path": "/var/mobile/.../test.mp4",
  "resolved_thumb_path": "/var/mobile/.../thumb.jpg",
  "receiver": "wxid_friend",
  "video_duration": 12.5,
  "generated_thumb": true,
  "downloaded": true,
  "max_size_bytes": 10485760,
  "max_size_mb": 10,
  "within_size_limit": true,
  "remote_size_known": true,
  "remote_size_bytes": 8123456
}

POST /send_video_from_url

用途:发送视频(URL 专用入口)。参数与 send_video 相同,区别是成功响应里会多一个 video_url 字段,且 downloaded 的判定按 URL 来源计算。

适用场景:你的服务端只想传链接时,用这个接口语义更明确。


POST /send_livephoto

用途:发送实况照片(Live Photo)。

请求字段:

字段 类型 必填 说明
receiver string ✅ 接收方
video_path string ✅ 视频部分,本地路径或 URL
image_path string — 静态图部分
still_image_time_ms int — 静态帧时间点(毫秒)
prefered_hevc bool — 是否优先 HEVC,默认 false

字段名 prefered_hevc 确实是这个拼法(少一个 r),不是笔误,请照写。

⚠️ 这两个可选字段在本接口(HTTP)上不做字符串转换,必须传 JSON 原生类型: - still_image_time_ms 必须传数字(传 "100" 会被当作没传) - prefered_hevc 必须传布尔值(传 "true" 会被当作 false)

这是 HTTP 接口与命令通道(长轮询/WebSocket)的一个真实行为差异——命令通道会做类型转换,HTTP 接口不会。

成功响应:

{
  "ok": true,
  "video_path": "...",
  "image_path": "...",
  "receiver": "wxid_friend"
}

失败响应:400 "send_livephoto is disabled" 或 400 + 具体原因。


POST /send_file

用途:发送文件(本地路径)。

字段 类型 必填 说明
receiver string ✅ 接收方
file_path string ✅ 本地绝对路径

成功响应:

{
  "ok": true,
  "resolved_file_path": "/var/mobile/.../report.pdf",
  "receiver": "wxid_friend",
  "file_name": "report.pdf",
  "file_size": 204800,
  "extension": "pdf"
}

POST /send_file_from_url

用途:发送文件(远程 URL)。

字段 类型 必填 说明
receiver string ✅ 接收方
file_url string ✅ 文件 URL

成功响应:比 send_file 多两个字段:

{
  "ok": true,
  "resolved_file_path": "...",
  "receiver": "wxid_friend",
  "file_name": "report.pdf",
  "file_size": 204800,
  "extension": "pdf",
  "source_url": "https://example.com/report.pdf",
  "downloaded": true
}

POST /send_link_card

用途:发送链接卡片。

字段 类型 必填 说明
receiver string ✅ 接收方
title string ✅ 卡片标题
url string ✅ 跳转链接
description string — 描述文字
thumb_url string — 缩略图 URL
thumb_path string — 缩略图本地路径
source_user_name string — 来源账号标识
source_display_name string — 来源显示名

成功响应:

{
  "ok": true,
  "receiver": "wxid_friend",
  "title": "标题",
  "url": "https://example.com",
  "thumb_url": ""
}

POST /send_music_card

用途:发送音乐卡片。注意:这个接口内部走的是转发链路(relay_* 字段会体现在响应里),不是直接构造消息。

字段 类型 必填 说明
receiver string ✅ 接收方
title string ✅ 歌曲名
desc string — 描述
url string — 音乐链接
data_url string — 音频数据地址
song_album_url string — 封面图
app_id string — 来源 App ID
app_name string — 来源 App 名称
song_lyric string — 歌词;兼容 songlyric、songLyric

别名表(这个接口为了兼容历史调用方,别名特别多):

主字段 兼容别名
receiver toUser、to、chatId、target
desc description
url musicUrl、music_url
data_url dataurl、dataUrl
song_album_url songalbumurl、songAlbumUrl、thumbUrl、thumb_url
app_id appId
app_name appName
song_lyric songlyric、songLyric

重要:url、data_url、song_album_url、app_id、app_name 这五个字段不传会用内置默认值兜底(默认指向一个示例音乐)。也就是说缺参数不会报错,会发出去一张指向默认歌曲的卡片。要发自己的音乐,这五个字段请全部显式传入。

请求示例(URL 和应用信息均为占位值,需替换):

{
  "receiver": "filehelper",
  "title": "歌曲标题",
  "desc": "歌手 - 专辑",
  "url": "https://music.example.com/song/1",
  "data_url": "https://media.example.com/song/1.mp3",
  "song_album_url": "https://media.example.com/song/1.jpg",
  "app_id": "wx_example_music_app",
  "app_name": "音乐应用"
}

成功响应:

{
  "ok": true,
  "receiver": "wxid_friend",
  "title": "歌曲名",
  "desc": "",
  "url": "https://music.example.com/song",
  "dataurl": "...",
  "songalbumurl": "...",
  "app_id": "wx...",
  "app_name": "网易云音乐",
  "songlyric_length": 0,
  "relay_forward": true,
  "relay_chat": "filehelper",
  "relay_delete_staged": true
}

songlyric_length 为实际歌词的 UTF-16 长度;未提供歌词时为 0。

relay_* 字段说明该卡片是通过"先发到文件传输助手再转发"的链路实现的。如果你在文件传输助手里看到过残留,属正常现象,插件会清理。


POST /send_contact_card

发送已有联系人的原生名片。头像和昵称由微信联系人资料生成,接口不接收自定义头像或昵称。

字段 类型 必填 说明
receiver string 是 接收方真实 ID,可为好友或群
contact_id string 是 被推荐联系人的真实 user_name / wxid,或本机已有好友的完整微信号(alias);不能是群 ID
{"receiver":"filehelper","contact_id":"wxid_example"}

也可传 {"receiver":"filehelper","contact_id":"wechat_alias_example"}。先查询内部 ID;微信号使用本机联系人资料及已有好友列表精确匹配 alias,不按昵称或备注模糊选择,也不会自动联网搜索陌生人。若匹配不唯一则拒绝发送。成功响应的 contact_id 统一为解析后的真实 user_name。

成功响应示例:

{"ok":true,"submitted":true,"receiver":"filehelper","contact_id":"wxid_example","message_type":42}

普通名片外层类型为 42;OpenIM / OpenIM 客服联系人沿用微信原生判断为 66 / 67。ok:true、submitted:true 表示已调用原生消息提交方法,不代表收到服务器成功回执或对方已收到。名片发送已由用户在微信 8.0.80 验证通过;特殊联系人仍按微信实际返回处理。

POST /send_location

发送单次位置消息,外层类型 48。最少传收件人及经纬度;标题和地址可由微信坐标反查补全。

字段 类型 必填 说明
receiver string 是 接收方真实 ID,可为好友或群
latitude number 是 有限数值,范围 -90~90;不接受字符串、布尔值或 null
longitude number 是 有限数值,范围 -180~180;不接受字符串、布尔值或 null
title string 否 第一行文字,非空时直接使用,不反查
address string 否 地址文字;省略标题而提供地址时,地址也用作第一行文字
{"receiver":"filehelper","latitude":23.012345,"longitude":113.123456}

指定文字时:

{"receiver":"filehelper","latitude":23.012345,"longitude":113.123456,"title":"园区南门","address":"示例路 1 号"}

title、address 都为空或省略时,插件调用微信原生反查,等待回调最多 15 秒。优先采用带方向的地理描述,再尝试地址或 POI 名称;不能保证反查得到指定商户名称。需要精确显示名称时应传 title。传入的文字只接受字符串,空白串按省略处理,null 为参数错误。

反查失败、超时、结果没有可用文字或等待期间账号/登录会话变化时,不提交位置消息;返回 HTTP 400,响应保留诊断字段。经纬度同时为 0 时微信反查入口会拒绝,可通过显式 title 跳过反查。插件原样使用传入坐标,不转换坐标系,外部 GPS 坐标须先核对与微信地图的对应关系。

成功响应示例:

{
  "ok":true,"submitted":true,"receiver":"filehelper","message_type":48,
  "latitude":23.012345,"longitude":113.123456,
  "title":"园区南门","address":"示例路 1 号","title_source":"provided"
}

title_source 为 provided(显式标题)、address(地址作为标题)、wechat_geocode(微信反查)。submitted:true 仅表示已提交原生发送,不表示服务端确认送达。此接口和名片发送受插件启用、授权及发送开关约束。

POST /send_xml

用途:直接发送原始 appmsg XML。给高级用法准备的逃生舱。

字段 类型 必填 说明
receiver string ✅ 接收方
xml string ✅ 完整 XML 内容
type int ✅ appmsg 内部类型,链接卡片为 5、音乐卡片为 3
forward bool — 默认 false。true 时先暂存再走微信转发链路

说明:

  • xml 会原样写入消息,插件不做裁剪或重写。写错了就是发出去一条坏消息,插件不会帮你校验。
  • 想发微信官方客户端不支持的卡片类型,这是唯一的入口。

请求示例:

curl -X POST http://192.168.0.100:19088/send_xml \
  -H "Content-Type: application/json" \
  -d '{
    "receiver": "filehelper",
    "type": 5,
    "forward": false,
    "xml": "<msg><appmsg><title>XML接口测试</title><des>原始XML发送测试</des><action>view</action><type>5</type><url>https://example.com</url></appmsg></msg>"
  }'

成功响应:透传业务结果,ok 为 true,其余字段由发送链路返回。


POST /send_signal

用途:发送"小信号"(微信的轻量提醒)。

字段 类型 必填 说明
receiver string ✅ 接收方

说明:设计上只建议用于一对一联系人,不建议把群 ID 当接收方。

成功响应:

{
  "ok": true,
  "receiver": "wxid_demo_account",
  "cgi": 976,
  "event_flag": 5,
  "client_msg_id": 4976413716,
  "create_time": 1777500000
}

POST /send_pat

用途:发送"拍一拍"。

字段 类型 必填 说明
receiver string ✅ 要拍的人
room_id string 群聊必填 群 ID;私聊不传

成功响应:

{
  "ok": true,
  "receiver": "wxid_demo_account",
  "room_id": "48398681165@chatroom",
  "is_group": true,
  "scene": 0,
  "selector": "..."
}

7. 消息操作

POST /forward_message

用途:转发一条已存在的消息。

表情在同一请求内检查缓存、必要时触发微信原生下载,资源就绪后才转发并等待目标消息最终发送状态;无需先打开对话或另外调用下载接口。下载与发送各最多等待30秒。下载失败不会转发;已提交但无法确认会提示结果未知,此时不要自动重发,应核对目标消息。成功JSON保持原结构。

字段 类型 必填 说明
receiver string ✅ 转发目标
message_id string ✅ 被转发消息的 ID

成功响应:{"ok": true, "message_id": "...", "receiver": "..."}

前置条件:转发开关必须开启。


POST /revoke_message

用途:撤回一条消息。

字段 类型 必填 说明
message_id string ✅ 要撤回的消息 ID

成功响应:{"ok": true, "message_id": "..."}

⚠️ 微信自身对撤回有时限(2 分钟),超时会被微信拒绝并返回 400。插件不绕过这个限制。


8. 媒体下载与上传

适用插件:8.0.80。既有版本的图片、SILK 语音、视频、普通文件、表情的 HTTP 下载与上传,以及微信 CDN 上传已通过联调;视频和动画表情已验证缓存复用。三种通道共用同一媒体业务服务;本节分别给出当前通道的完整调用约定。

HTTP(均为 POST) 用途 默认等待
/download_message_media 准备消息媒体,返回手机本地副本 60 秒
/upload_message_media 自动准备媒体,再上传我们的服务器 60 秒
/upload_file_to_wechat_cdn 本地文件或外链文件上传微信 CDN 120 秒
/debug/message_media_probe 查看媒体或已有 CDN 任务状态 读取本地状态

HTTP 成功返回 200,参数或业务失败返回 400,授权限制沿用原约定(403)。客户端总超时建议设为 200 秒。业务接口的 timeout_seconds 是插件本次等待时间,范围 1~180 秒。

支持 image 图片、voice 语音、video 视频、file 普通文件(49/6)、emoji 普通表情。微信 WXGF/WXAM 表情转换为 GIF,保留动画;原本为 GIF、PNG、JPEG、WebP 的表情保留原格式。转换失败返回错误,不输出 .bin;游戏表情不支持导出。语音只输出微信原始 SILK,不转 MP3;Opus 返回 unsupported_voice_codec。

文件初始事件可能为 49/74。微信收到上传完成信息后,会以完成文件覆盖同一本地记录,同时更新服务器消息 ID。插件在账号、会话、localID、双方、类、创建时间和外层类型均匹配,并且完成文件明确声明覆盖原服务器 ID 时,可继续使用原事件的 message_id 下载或上传;正常业务刷新会保存最终 ID 别名。当前下载白名单仍是普通文件 49/6,不因诊断识别到 74/131 或完成类型 130 就直接开放下载。

0.8.79-82 已通过 HTTP 真机验证:原事件仍缓存为 74,数据库已是完成 6,使用原事件 ID 首次下载 CSV(8,126 字节)和 ZIP(12,155,230 字节)均成功,下载前本地无附件,结果为 downloaded:true、from_cache:false。用户现已确认相关媒体业务在微信 8.0.80 验证通过;仍须满足下文的索引、原聊天记录与文件类型条件。

旧 /download_message_image(含 /debug/download_message_image 别名)和 /upload_message_image 已废弃,仅保留兼容。新接入分别使用 /download_message_media 和 /upload_message_media;图片仍传 message_id,类型自动识别,返回字段按统一媒体接口读取。长轮询 / WebSocket 的旧 upload_message_image 命令同样保留兼容,改用 upload_message_media。

上传接口受插件“消息发送”开关限制;下载和探针不受此开关限制。授权沿用当前通道约定。以下消息 ID、文件路径、资源 ID 和域名均为示意,需替换成实际值。

8.1 下载媒体

请求: POST /download_message_media,Content-Type: application/json。

{
  "message_id": "1234567890123456789"
}
参数 必填 说明
message_id 是 消息事件中的 body.message_id(内部 msg_id 不对外输出),必须为字符串,避免大整数精度丢失;文件完成覆盖关系核验通过后仍可使用原 74 事件 ID
media_type 否 指定时校验是否与原消息匹配;可省略
timeout_seconds 否 本次总等待时间,默认 60,范围 1~180 秒,数字

只支持插件已观察到且索引仍有效的消息,不增加任意历史消息查询。

已成功保存完整定位索引的消息可在同一设备、同一账号重启后继续定位;每账号保留最近 2000 条定位记录,内存最多保留 200 个消息对象。原聊天记录须仍存在,未登记、索引被淘汰或身份不匹配时不能仅凭 ID 找回。原事件 ID 刷新到完成文件后,原 ID 和已登记的最终 ID 均可使用;重复下载可复用完整副本。用户已确认相关媒体业务在微信 8.0.80 验证通过,跨重启定位仍受上述保存条件约束。

下载成功示例(数据、路径均为示意):

{
  "ok": true,
  "message": "已使用缓存文件",
  "message_id": "1234567890123456789",
  "media_type": "voice",
  "downloaded": true,
  "from_cache": true,
  "resolved_local_path": "/var/mobile/Containers/Data/Application/EXAMPLE/tmp/webridge_media/ACCOUNT_HASH/1234567890123456789/voice.silk",
  "resolved_file_name": "voice.silk",
  "file_size": 18576,
  "mime_type": "application/octet-stream",
  "md5": "0123456789abcdef0123456789abcdef",
  "codec": "silk",
  "voice_length_ms": 3260,
  "duration_ms": 42,
  "build_marker": "webridge_build_20261106_settings_update_8080",
  "request_id": "media_download_001",
  "version": "8.0.80-2"
}

resolved_local_path 是手机沙盒路径,服务器无法直接 GET。需要服务器文件时调用上传接口。voice_length_ms 为语音时长,取不到为 0;duration_ms 为接口耗时。语音保持原字节,不播放、不主动设置已听状态。

缓存命中(插件副本或请求开始时微信已具备完整文件)返回 from_cache:true、message:"已使用缓存文件";新下载返回 false、"下载完成"。图片沿用现有原生下载和解码策略,可能回退微信提供的标准清晰度,不承诺原图。

视频同时检查下载队列、声明大小和副本可读性;原生状态缺失时,必须核对完整文件 MD5 才允许导出,不能仅凭大小一致放行。表情转换后的 file_size、md5 和 mime_type 对应实际导出文件;GIF 的 MIME 为 image/gif。旧 emoji.bin 缓存会自动重新准备。

本次等待超时返回 media_timeout;后台资源准备最多继续到 180 秒。重复相同消息请求会合并正在进行的准备任务;可稍后重试同一个 message_id。

8.2 上传我们的服务器

请求: POST /upload_message_media,Content-Type: application/json。

{
  "message_id": "1234567890123456789",
  "timeout_seconds": 120
}

沿用下载接口参数;timeout_seconds 默认 60,覆盖本次等待准备和 HTTP 上传。另有可选 upload_url、request_id。HTTP 未传 request_id 时生成并返回一个真实请求 ID;当前 HTTP 请求 ID 会写入上传的 command_request_id。

默认 upload_media 就是设置里的业务服务器 base URL 加 /agent/upload_media,保留 base URL 的路径前缀。未配置业务服务器时须传入完整 HTTP/HTTPS upload_url。

请求体为 multipart/form-data,文件字段为 file。文字字段:

字段 内容
message_id / resolved_source_message_id 来源消息 ID
command_request_id 本次真实 HTTP / 远程请求 ID
file_name / file_size / mime_type / md5 实际上传副本的文件名、大小、MIME、MD5
media_type image / voice / video / file / emoji
account_id / device_id / session_id 沿用现有账号、设备和会话字段
sender_id / chat_id / room_id / is_group 来源用户和会话,is_group 为文字 true / false
codec / voice_length_ms 仅语音,分别为 silk 和时长毫秒数

服务器必须返回 HTTP 2xx 和 JSON {"ok":true,"asset_id":"实际资源ID"},其中 asset_id 为非空字符串。可以额外返回 url、local_path,分别映射为 server_url、server_local_path。仅有 HTTP 200 状态、HTML 页面、空响应或缺少 asset_id 都判为失败。视频、文件通过磁盘 multipart 文件上传,不把整个请求体装入内存。

成功返回下载元数据,另加:

{
  "ok": true,
  "message": "上传成功",
  "message_id": "1234567890123456789",
  "media_type": "voice",
  "downloaded": true,
  "from_cache": true,
  "uploaded": true,
  "asset_id": "asset_voice_example",
  "upload_http_status": 200,
  "server_url": "https://example.com/media/asset_voice_example",
  "request_id": "media_upload_001",
  "version": "8.0.80-2",
  "build_marker": "webridge_build_20261106_settings_update_8080"
}

from_cache 仅说明源媒体来自本地;每次调用仍向服务器发起上传。上传失败可复用缓存重试;服务器是否按 command_request_id 去重由服务器实现。旧 /upload_message_image 也复用新的磁盘 multipart helper,成功同样要求 ok:true 和非空 asset_id;旧图片接口其他字段保持原约定。

8.3 上传微信 CDN

请求: POST /upload_file_to_wechat_cdn,Content-Type: application/json。

{
  "request_id": "cdn_example_001",
  "file_path": "/var/mobile/Containers/Data/Application/EXAMPLE/tmp/webridge_media/ACCOUNT_HASH/1234567890123456789/voice.silk",
  "timeout_seconds": 120
}

也可以传 {"request_id":"cdn_example_002","file_url":"https://example.com/demo.pdf"}。

参数 必填 说明
request_id 是 1~128 字符字符串,重试时保持原值
file_path / file_url 二选一 手机绝对路径 / 可下载的 HTTP(S) 文件地址
timeout_seconds 否 默认 120,范围 1~180 秒

首版统一通过“给文件传输助手发送普通文件”完成上传,因此允许产生一条 filehelper 文件消息。下载得到的语音、图片等字节也可提交,但返回的都是普通文件附件票据,不能直接当作图片、语音、视频或表情专用发送票据,也不是公开下载 URL。

只有本次确切消息完成发送,且账号、localID、文件大小、MD5、服务端消息 ID、file_id、AES key 均满足校验时返回成功:

{
  "ok": true,
  "message": "微信 CDN 上传成功",
  "request_id": "cdn_example_001",
  "uploaded": true,
  "pending": false,
  "stage": "uploaded",
  "cdn_type": "file",
  "receiver": "filehelper",
  "file_name": "voice.silk",
  "file_size": 18576,
  "md5": "0123456789abcdef0123456789abcdef",
  "local_id": 123,
  "server_id": "1234567890123456790",
  "cdn": {
    "file_id": "微信实际返回值",
    "aes_key": "微信实际返回值",
    "attach_id": "有则返回"
  },
  "staging_deleted": false,
  "cleanup_status": "pending_ticket_validation",
  "version": "8.0.80-2",
  "build_marker": "webridge_build_20261106_settings_update_8080"
}

当前保留临时消息,staging_deleted:false。不启用按条清理,以保留后续发送所需的票据;本包不会因超时删除发送中的消息。CDN 密钥只出现在成功业务响应中,探针不返回密钥或完整 XML。

同账号相同 request_id 绑定原任务,重复参数复用等待或结果,不再次发送;本地文件还存在时会核对内容变化,参数变化返回 request_id_conflict。同 URL 重试指原任务的下载结果,不重新抓取 URL。幂等记录保存在当前微信进程内,重启后失效;结果未知时不要重启后盲目重提。

等待超时返回 ok:false,error:"media_timeout",pending:true;保留同一个 request_id 和文件参数继续调用,或用探针查询。后台最多观察 15 分钟;其后业务接口仍会按原消息重查迟到结果。最多保留 128 个 CDN 请求 ID,达到上限返回 cdn_task_limit,不会淘汰旧任务而隐式重传。

外链文件单次上限 512MB,开始前需预留相应缓存配额;本地文件受全局 1GB 配额限制。源文件、媒体缓存和上传体并存时,实际可用单文件大小会更低。空间不足明确返回错误,不扩大配额。

8.4 调试探针

查询某条消息,不触发下载、播放或发送:

请求: POST /debug/message_media_probe,Content-Type: application/json。

{
  "message_id": "1234567890123456789"
}

消息分支返回 probe_version:2,允许诊断当前下载白名单未支持的 49/74 等消息。探针不触发下载、上传、播放或发送,不回写消息缓存/定位关系,也不创建或清理媒体缓存、不更新缓存使用时间。它仍返回消息/扩展/服务类、语音格式和时长、视频下载队列信息及关键 selector 签名。

database_message 是按已登记会话和 localID 重读、基础身份核验通过的数据库对象快照,cached_message 是已缓存对象在本次诊断中的快照;无对象时为 null。顶层快照优先取数据库,否则取缓存,由 probe_source 标明。两个对象可能来自同一个原生对象,不能把两份结果视为变更前后快照。以下快照字段同时适用于顶层和两份对象:

字段 类型与说明
probe_version / probe_source 顶层整数 2;来源为 database / cache
message_class / extension_class / message_manager_class 字符串;最后一项在顶层,未取得类名时为空字符串
media_type / type_supported 当前下载白名单识别类型,未支持时类型为空字符串;支持标志为布尔或 0/1,不表示文件已准备好
diagnostic_media_type 只读诊断类型;49/6、74、130、131 均可按 file 检查路径和状态,不据此放宽下载白名单
raw_message_type / app_msg_type / wrap_app_msg_type / extension_app_msg_type 整数或 null;分别为外层类型、按字段所属对象读取的 app 类型、直接从 wrap 和扩展读取的 app 类型;非 app 消息的 app_msg_type 为 null
m_uiMesLocalID / m_n64MesSvrID / m_overwriteNewMsgId 十进制字符串或 null,避免大整数精度丢失;覆盖编号为 0 不能证明有覆盖关系
bAppMsgCompleteFlag / m_bAppAttachExistInSvr 原生布尔或 0/1,未取得时为 null;消息完成与附件是否已经下载是不同状态
m_uiDownloadStatus / m_uiUploadStatus 原生整数或 null;缺失的 null 不能按 0 解释
IsFileMsg / IsFileUploadingMsg 原生分类结果,布尔或 null;方法不可用/签名不匹配时为 null,上传中分类不等于当前上传进度
native_path / native_size / expected_size 手机原生路径字符串、实际字节数和声明字节数;未取得路径为空,未知或文件不存在时大小为 0
native_file_exists / native_file_readable / size_matches 布尔或 0/1;大小匹配仅表示声明大小大于 0 且与实际相同,不代表完整性校验通过
download_status / native_complete / native_downloading 快照下载状态整数(缺失时为 0)、原生下载完成/进行中布尔;不修正数据库状态,不执行 MD5 或视频解码校验
cache_ready 顶层布尔或 0/1,表示插件正式副本可用;为假不代表微信一定没有原文件
video_queue_known / has_expected_md5 / raw_video 视频队列查询是否可用、是否有长度为 32 的声明 MD5、是否按原始视频检查;布尔或 0/1,不返回声明 MD5 内容
voice_cancelled / voice_length_ms / voice_format 语音取消标志、时长毫秒和格式编号;整数,未知时为 0
has_m_nsAppAttachID / has_m_nsMsgAttachUrl / has_m_nsAesKey / has_m_authkey 布尔或 0/1,仅表示原生字段是否非空,不返回附件标识或密钥值
xml 仅 app 消息提供安全摘要;见下方说明,不返回原 XML
signatures 顶层对象,包含原生下载/队列方法的签名与可用性诊断

xml.parsed 表示 XML 是否解析成功;失败时摘要可能只有此字段。xml.type、xml.totallen、xml.overwrite_newmsgid 为根 appmsg 中的十进制字符串或 null;xml.has_attachid、xml.has_cdnattachurl、xml.has_aeskey、xml.has_authkey 为布尔或 0/1,只报告是否非空。不要把不存在的值当作 0,也不要把编号转成 JSON 数字。

lookup 字段/状态 说明
registered_local_id / registered_server_id 原定位记录中的十进制编号字符串;无有效记录时省略
refresh_accepted 布尔或 0/1,仅表示业务定位刷新规则是否接受,不表示类型受支持或附件已可下载;数据库仍为 74、服务器 ID 未变时也可为 1
database_status=ok 数据库对象可被定位规则接受,包括完整身份和明确文件覆盖关系核验通过
server_id_changed 基础身份核验通过,但服务器 ID 变化未被业务规则接受
lookup_not_found 没有当前账号可用的定位记录,可仍有缓存对象供诊断
native_unavailable 原生数据库读取入口不可用或签名不匹配
message_not_found_or_identity_mismatch 未取得同一消息记录,或基础身份不匹配
account_changed 诊断期间账号变化,不能使用原账号数据

完成覆盖已可接受、附件尚未下载的成功响应节选(所有编号为示意):

{
  "ok": true,
  "message": "已读取媒体状态,未触发下载或发送",
  "probe_version": 2,
  "probe_source": "database",
  "message_id": "1234567890123456789",
  "media_type": "file",
  "type_supported": 1,
  "app_msg_type": 6,
  "native_file_exists": 0,
  "native_size": 0,
  "expected_size": 8126,
  "cache_ready": 0,
  "cached_message": {"app_msg_type": 74, "m_uiMesLocalID": "4096", "m_n64MesSvrID": "1234567890123456789"},
  "database_message": {"app_msg_type": 6, "m_uiMesLocalID": "4096", "m_n64MesSvrID": "1234567890123456790", "m_overwriteNewMsgId": "1234567890123456789"},
  "lookup": {"database_status": "ok", "refresh_accepted": 1, "registered_local_id": "4096", "registered_server_id": "1234567890123456789"},
  "build_marker": "webridge_build_20261106_settings_update_8080"
}

消息探针 ok:true 只说明诊断读取成功。调用下载/上传业务后,才会执行实际资源准备并在成功定位刷新后保存别名。两份快照均无对象时返回 message_not_found,账号变化返回 account_changed;HTTP 失败为 400,授权失败沿用 403。视频原生状态缺失时 native_complete 可以为 false,而业务接口仍可在完整文件校验后成功。

查看已有 CDN 任务,不创建新任务,也不返回 AES / XML:

请求: POST /debug/message_media_probe,Content-Type: application/json。

{
  "request_id": "cdn_example_001"
}

探针 ok:true 表示读取成功;operation_ok、stage、pending、task_finished、task_error 表示上传状态。has_file_id / has_aes_key 仅表示字段是否存在。业务成功结果及票据仍从 /upload_file_to_wechat_cdn 获取。

探针的 message_id 和 request_id 二选一。查询 CDN 时,请求和成功响应里的 request_id 均为被查询的原上传任务 ID。

8.5 缓存文件规则

  1. 顺序:插件完整副本 → 微信完整本地文件 → 原生下载。同账号、消息和媒体类型的并发准备合并;同时最多准备 32 项。
  2. 插件副本位于 tmp/webridge_media/<账号摘要>/<消息ID>/;微信原文件不移动、不删除。写 .part,校验大小、必要 MD5 和 SILK 头后原子改名;只返回正式副本。
  3. 记录文件名、大小、实际 MD5、类型和最近使用时间,不记录 AES 或 XML。命中前检查文件是否存在、可读、非空、大小一致,语音另核对 SILK 头;旧 emoji.bin 不再直接命中,会从微信资源重新导出。
  4. 最近使用后保留 1 小时,所有账号共用 1GB 上限,包含本次新增副本、CDN 来源暂存和 multipart 临时文件。空间不足先淘汰最久未使用的空闲项,在用项不删,仍不足返回 cache_space_insufficient。已有其他发送目录继续使用其原有规则。
  5. 启动及新任务开始时清理;上传成功也不马上删除。系统可提前回收 tmp,文件丢失后会重新准备。

8.6 后端接收服务复用

聊天媒体与朋友圈媒体可以使用同一个后端应用、同一个端口和同一套存储。 当前上传格式不同,推荐在现有业务后端提供两个接收入口,共用保存文件和生成访问地址的逻辑:

用途 推荐接收路由 手机发出的请求 成功条件
聊天媒体回传 POST /agent/upload_media multipart/form-data,文件字段 file,其余字段见本节上传约定 HTTP 2xx,JSON ok:true 且非空 asset_id
朋友圈媒体回传 PUT /uploads/{resource_id} 原始文件正文,Content-Type 为实际图片/视频 MIME;插件也支持原始正文 POST 完整接收并保存后返回 HTTP 2xx;插件还核对发送字节数

朋友圈使用本篇 朋友圈媒体下载 中的 upload 对象:url 指向上述接收地址,resource_id 由后端分配,method 默认 PUT,headers 可携带鉴权。插件不解析朋友圈上传响应正文,只读取状态码;响应不要超过 64KiB。朋友圈首次受理不等于文件上传完成,仍需等 moments_result 或查询任务,确认 status:"succeeded"、media_ready:true、delivery:"upload"、upload_completed:true。上传结果未知时先按 resource_id 核对后端,插件不会自动重传。

仅处理 multipart 的 /agent/upload_media 不能直接接收朋友圈原始正文,把朋友圈 method 改成 POST 也不会改变正文格式。后端增加原始正文入口即可,插件不需要为了共用后端而改动。两个入口可以共用资源表、文件目录和 GET /files/...;若沿用朋友圈网页示例,需支持按 resource_id 读取,视频读取需支持 Range。

upload_file_to_wechat_cdn 是手机通过微信原生链路上传微信 CDN,不需要自有上传接收服务。其 file_url 可以使用上述后端已有文件地址;返回的普通文件附件票据不能代替朋友圈发布专用上传结果。

仓库中的 demo/消息媒体上传接收端/media_upload_server.py 与 demo/朋友圈媒体上传接收端/server.py 目前仍是两个独立示例,尚未合并;正式接入推荐复用同一业务后端,按本节支持两个入口。

8.7 调用检查与常见错误

HTTP 调试可导入同目录 Apifox 定义(资料未收录),接口位于“08 媒体处理”;旧图片接口为废弃状态。

  1. 用新收到事件的 body.message_id 调下载,再调一次检查 from_cache:true;核对文件名、MIME、大小和 MD5。语音应为 SILK,WXGF/WXAM 动画表情应导出 GIF。
  2. 调上传我们的服务器,确认文件实际落盘、asset_id 非空;from_cache:true 只表示手机复用源文件,每次请求仍会上传。
  3. 下载或上传等待超时可重试同一 message_id;微信 CDN 超时则必须保留原 request_id 和文件参数,避免重复发送。CDN 临时消息目前保留,删除后的票据消费不在已确认范围内。
  4. 下载失败时同时提供业务响应和媒体探针响应;CDN 结果未知时用原上传 ID 查询,探针不含可消费票据。

常见错误:invalid_message_id、media_type_mismatch、message_not_found、not_logged_in、account_changed、unsupported_media_type、unsupported_voice_codec、media_timeout、cache_space_insufficient、media_checksum_mismatch、server_upload_failed、upload_url_required、request_id_conflict、cdn_task_limit、cdn_result_unknown。

外层 49、内层仍为 74/131 时,保留错误码 unsupported_media_type,提示为“该文件处于对方或我们,上传尚未完成(上传中)阶段,或完成消息尚未同步,请稍后使用同一 message_id 重试”。这时应等待本机或对方上传完成,且完成消息同步到本机,再用原 ID 调用;不会自动等待上传完成或绕过类型校验。其他不支持的类型仍提示“仅支持图片、语音、视频、普通文件和普通表情”。

等待超时结果示例:

{
  "ok": false,
  "error": "media_timeout",
  "error_code": "media_timeout",
  "message": "本次等待超时,原下载继续;可用同一 message_id 重试",
  "message_id": "1234567890123456789",
  "media_type": "video",
  "duration_ms": 10001,
  "request_id": "media_download_001",
  "version": "8.0.80-2",
  "build_marker": "webridge_build_20261106_settings_update_8080"
}

HTTP 业务失败优先读取 error_code / error,中文原因读取 message。


9. 联系人与好友

POST /friends

用途:好友列表,分页。

字段 类型 必填 默认 说明
limit int — 100 每页条数
offset int — 0 偏移量
keyword string — — 关键词过滤

成功响应:

以下为响应结构节选,数组中的 ... 表示省略内容,不能直接作为 JSON 解析:

{
  "ok": true,
  "keyword": "",
  "limit": 100,
  "offset": 0,
  "total": 256,
  "has_more": true,
  "items": [ ... ]
}

支付姓名字段只反映缓存,需用 /friend_pay_name 按需查询。字段详见 列表与群成员返回字段。翻页时不断增大 offset,直到 has_more 为 false。

每个好友条目恒含 add_time(Unix 秒)与 add_time_text(固定北京时间 UTC+8,YYYY-MM-DD HH:mm:ss);未知时两者均为 null。无需新增请求参数,分页只为当前页读取添加时间。完整字段、空值规则和示例见联系人摘要对象。


POST /friends_all

用途:一次性返回全部好友(不分页)。

字段 类型 必填 说明
keyword string — 关键词过滤

成功响应:

以下为响应结构节选,数组中的 ... 表示省略内容,不能直接作为 JSON 解析:

{
  "ok": true,
  "keyword": "",
  "total": 256,
  "friend_count": 256,
  "official_account_count": 12,
  "work_account_count": 0,
  "system_account_count": 4,
  "chatroom_count": 38,
  "stranger_count": 0,
  "cached_contact_count": 310,
  "items": [ ... ]
}

支付姓名字段只反映缓存,需用 /friend_pay_name 按需查询。字段说明见 列表与群成员返回字段。

每个好友条目同样恒含 add_time 与 add_time_text,格式、时区和空值规则与 /friends 一致,只为筛选后返回的好友读取时间。HTTP 与同名命令均支持,无需新增参数。详见联系人摘要对象。

items 仅包含按当前通讯录规则筛出的普通好友;公众号、企业微信、系统号、群聊及陌生人仅参与各自分类计数。total 是返回的好友条数,cached_contact_count 是原始缓存联系人条数。 ⚠️ 好友多时响应体会很大。日常使用建议用 friends 分页接口。

POST /friend_pay_name:阻塞查询好友或群成员支付姓名末字

单次调用等待微信回调后返回最终结果,不返回 querying 中间结果,无需再次查询任务状态。微信主线程保持异步运行。

这里的“实名相关查询”指微信支付脱敏姓名的末字查询,不提供完整实名,也不能用查询结果判断对方是否已实名认证。

  • id 必填,使用好友列表或 room_members 返回的个人 account_id。好友直接查询;非好友自动查找双方均在其中的普通微信群,无需传 room_id。不支持自己、群 ID、公众号、企业微信或系统号。
  • refresh 为布尔值,默认 false。当前好友或共同群场景有缓存时立即返回终态(包括已缓存的失败);true 强制刷新或失败重试,并等待本次结果。同一目标、同一场景正在查询时合并等待;关系或群上下文变化后重新查询。
  • 自动查找依赖本地群列表和成员资料;未找到可用共同群或资料未就绪时返回 failed 和中文原因。存在多个共同群时选择一个已核实的普通群,不轮询所有群发起支付查询。
  • 原生查询串行执行,最多 32 个待处理请求;30 秒超时包含排队时间,接口等待保护上限约 31 秒。调用方超时建议至少 40 秒。
  • 仅查询转账前信息,不提交金额或付款确认。结果只保留在当前账号会话内存中,账号或联系人服务会话变化后清空。
pay_name_status HTTP ok/命令外层 ok 含义
ok true / 1 已取得有效的姓名末字,pay_name_last_char 非空
unavailable true / 1 微信业务响应成功,但没有可用末字;不能据此判断未实名或被单删
failed false / 0 参数、账号、兼容、网络、业务或超时失败,error 给出原因

friends、friends_all 只附带好友场景缓存,本身不发起支付查询,群内非好友不会因此加入好友列表。列表仍可能显示 not_queried 或正在处理的 querying;单人查询接口和命令只返回上表中的终态。支付姓名字段不改变昵称、备注或 display_name,不提供完整姓名。

自动选择共同群的功能已由用户在微信 8.0.80 验证通过。

请求示例:

curl --max-time 40 --request POST 'http://192.0.2.10:19088/friend_pay_name' \
  --header 'Content-Type: application/json' \
  --data-raw '{"id":"wxid_example","refresh":false}'

本次请求等待后直接返回以下终态(姓名为虚构值):

{
  "ok": true,
  "account_id": "wxid_example",
  "pay_name_last_char": "明",
  "pay_name_status": "ok"
}

查询结果和业务失败均为 HTTP 200。失败时 ok=false、pay_name_status=failed,原因在 error;例如超时为“支付姓名查询超时,可使用 refresh 重试”。授权失败仍使用通用 HTTP 403。客户端兼容 ok 的布尔值和数字 0/1。

POST /search_contact / POST /add_friend

用途:搜索普通个人联系人,并主动发起添加或验证申请。

主动添加使用两步调用:先搜索获得 contact_ref,再用该引用提交验证消息。支持普通个人联系人;公众号、群、OpenIM 和当前账号不提供可添加的引用。friends.keyword 仍只过滤本地好友列表。

搜索参数为 {"keyword":"示例微信号"},keyword 必须是 1–256 个字符的字符串。支持微信实际允许搜索的微信号、手机号等,不保证任意原始 wxid 可搜索。搜索成功示例(依据用户提供的 HTTP 真机回包整理,身份和头像链接已替换):

{
  "ok": true,
  "status": "found",
  "contacts": [{
    "contact_ref": "fc_example_ref",
    "username": "example_user",
    "nick_name": "示例昵称",
    "alias": "example_alias",
    "avatar_url": "https://example.com/avatar/132",
    "avatar_hd_url": "https://example.com/avatar/0",
    "sex": 1,
    "country": "",
    "province": "",
    "city": "",
    "signature": "",
    "supported": true,
    "is_friend": true,
    "source": "wechat_id"
  }],
  "expires_in": 300,
  "native_ret": 0,
  "stage": "search",
  "request_submitted": true,
  "event_id": 42,
  "request_cgi": 106,
  "message_type": 0,
  "transport_error_type": 0,
  "transport_error_code": 0
}

contacts[] 同时返回本次搜索取得的公开资料,无需先加好友,也不会额外发起资料查询:

字段 类型 说明
avatar_url string 头像链接;微信未返回时为空字符串
avatar_hd_url string 大图头像链接;微信未返回时为空字符串
sex integer 性别:0 未知、1 男、2 女;未取得时为 0
country string 国家/地区,沿用微信返回值;未取得时为空字符串
province string 省份,沿用微信返回值;未取得时为空字符串
city string 城市,沿用微信返回值;未取得时为空字符串
signature string 个性签名;未取得时为空字符串

以上字段在每个候选中均返回,是否有值取决于微信本次回包及对方公开资料;地区是个人资料填写值,不代表实时位置。它们不改变 supported 或 contact_ref 的规则。

country、province、city、signature 为空字符串时,表示本次搜索未取得对应资料,不影响 status:found;仅凭该结果无法区分对方未设置资料,还是微信搜索回包未提供。

is_friend 来自本地普通好友判断。为 true 时无需再发好友申请,正常调用 add_friend 会返回 already_friend。supported:true 表示候选类型符合当前添加流程,不代表对方是陌生人;已有好友也可能同时返回 supported:true 和 contact_ref。

source 为 wechat_id、phone 或 qq,由微信搜索匹配类型决定。username 是微信原生返回的标识,可能是加密标识,不能一律当成稳定 wxid。多候选由调用方选择;supported:false 的候选没有 contact_ref,不能提交添加。确认未找到时返回 ok:true,status:not_found,contacts:[];传输错误、解析错误和业务失败返回 ok:false,不能当成“用户不存在”。

添加参数:

{"contact_ref":"fc_example_ref","say_content":"你好,我是某某"}

contact_ref 必填,只能使用本账号本次登录会话的搜索结果;say_content 可省略,默认为空字符串,不接受数字或 null。输入会去除首尾空白,并按微信原生长度规则校验;过长时返回 INVALID_SAY_CONTENT,不会悄悄截断发送。不能直接传 username、scene、opcode 或票据替代引用。好友添加遵循插件发送开关。

添加成功示例:

{
  "ok": true,
  "status": "request_sent",
  "username": "example_user",
  "is_friend": false,
  "contact_ref": "fc_example_ref",
  "native_ret": 0,
  "stage": "send_verification",
  "request_submitted": true,
  "event_id": 43,
  "request_cgi": 137
}
status ok 含义及下一步
already_friend true 本地联系人服务确认已经是普通好友,本次未发添加请求,native_ret:null
request_sent true 微信确认验证申请发送成功,等待对方同意;不能当成已加好友
added true 微信添加成功且原生后处理完成,本地普通好友判断通过
pending_sync true 微信添加成功且原生后处理已运行,本地好友状态尚未确认;稍后通过 friends/friends_all 核对
needs_user_action false 微信要求人工处理或预检查失败;在微信内查看,不自动确认或绕过限制
timeout false 30 秒内未取得最终结果,结果不确定;先核对好友状态,不自动重发
failed false 参数、会话、运行时或微信请求失败,读取 error_code、error、native_ret

引用在插件内存保留 300 秒,最多 50 个;这个时间是本地缓存策略,不代表微信票据寿命。重启、退出登录或账号/上下文变化后必须重新搜索。相同引用及相同规范化消息的并发调用共享操作,完成后在引用有效期内复用结果;消息不同返回 CONTACT_REF_CONFLICT。同目标的另一引用正在添加时返回 ADD_IN_PROGRESS。超时后的相同引用仍返回原结果,不会自动重发。跨引用、跨重启和超过缓存期不承诺去重,后端也应避免重复下发。

两项操作均在当前请求内等待,插件操作期限为 30 秒,调用方建议至少等待 40 秒。native_ret 未取得微信业务结果时为 null;不能把 null 当 0。搜索成功或微信添加成功为 0,部分未找到搜索结果保留微信 -4。stage 为 preparing、search、precheck、add_contact 或 send_verification。request_submitted 只表示搜索/添加请求获原生受理(预检查不单独计入),不代表服务器已成功处理;request_cgi 为当前请求/最近回包的 CGI(搜索 106、添加 137、补取联系人 182、预检查 11568);搜索的 event_id 为提交返回的 ID,添加为最近原生回调的 ID,尚无回包时为 null。它们仅用于诊断。

常见错误码:INVALID_KEYWORD、INVALID_PARAMETERS、INVALID_SAY_CONTENT、SEND_DISABLED、ACCOUNT_UNAVAILABLE、ACCOUNT_CHANGED、CONTACT_REF_EXPIRED、CONTACT_REF_CONFLICT、ADD_IN_PROGRESS、CANDIDATE_CACHE_FULL、TOO_MANY_REQUESTS、NATIVE_API_UNAVAILABLE、REQUEST_NOT_STARTED、PRECHECK_NOT_STARTED、PRECHECK_FAILED、WECHAT_INTERACTION_REQUIRED、WECHAT_REQUEST_FAILED、SEARCH_FAILED、WECHAT_TRANSPORT_FAILED、RESPONSE_INCOMPLETE、RESPONSE_INVALID、FRIEND_OPERATION_TIMEOUT。微信返回普通 -44 时最多一次进入原生发送验证消息入口;交互限制和预检查失败不会自动继续。

探针接受 {} 或 {"contact_ref":"fc_example_ref"}。它不发送搜索/好友申请,返回 search_runtime、add_runtime(ready 及各 selector 的 compatible/encoding)、logged_in、send_enabled、cached_candidates、pending_operations、contact_ref_valid、expires_in、has_antispam_ticket、reference_status 和 last_operation。last_operation 只保留最近一次操作的状态、阶段、返回码和受理信息;不包含账号、关键词、验证消息或原始票据。出现 NATIVE_API_UNAVAILABLE 时先调用探针定位不兼容项。

已取得用户提供的 HTTP 真机搜索成功回包,确认本次已有好友场景返回头像、大图头像、性别和 is_friend:true,地区及签名为空。用户现已确认搜索与添加好友功能在微信 8.0.80 验证通过;资料字段是否有值仍以微信本次回包为准,人工处理和超时按本节状态规则处理。

HTTP 的搜索和添加结果(包括参数错误、业务失败和超时)均保留完整 JSON,通常为 HTTP 200,必须读取 ok 和 status;授权失败仍为 HTTP 403。不要用 HTTP 200 判定添加成功。

-44 和发送状态的判断:stage:add_contact 表示直接添加阶段;request_submitted:true 只表示原生请求受理,不能据此认定验证申请已经发出。新增 verification_attempted 表示是否进入过发送验证消息入口;只有最终 status:request_sent 才表示微信确认验证申请发送成功。旧包在 add_contact 返回 needs_user_action,-44 时可能尚未进入验证消息阶段。

交互条件按现有原生链路判断:spam 提示标题、正文及 ctx 同时非空才要求人工确认;仅存在空的 verifyUserSpamInfo 对象或仅有 ctx,不会拦住普通 -44 的一次验证消息转换。微信原生可处理的 XML 提示、预检查失败及其他明确限制仍停止自动继续。

脱敏 failure_detail 保留最近一次错误分类,即使随后发送验证成功也可能保留此前的 verification_required:reason 为 spam_challenge、native_error_dialog、error_xml_unreadable、precheck_failed、verification_required 或 wechat_error;native_ret 为该次错误码;并提供 has_spam_info、has_spam_title、has_spam_detail、has_context、spam_challenge、has_error_xml、xml_show_type、xml_handled、xml_unreadable。不返回原始 ctx、XML、票据或提示文本。最终结果以外层 status/native_ret 为准,不能把历史 failure_detail 当成最终失败。

friend_add_probe 的 last_operation 同时返回 verification_attempted 和 failure_detail;群场景也可在 room_candidate.last_result 查看。该判定和诊断同时用于 add_friend 与 add_room_friend,不新增接口。

成功回包按实际请求区分:CGI137 的 opcode 1(直接添加)仍要求联系人标识;opcode 2(发送验证消息)允许回包缺少用户名,插件继续执行微信原生申请记录保存和成功回调,收到 contactSendRequestOk: 后才返回 request_sent。不会仅凭 native_ret:0 合成成功。旧包在 send_verification 阶段可能将这种正常回包误报为 RESPONSE_INCOMPLETE,并把已取得的 0 丢成 null;该旧结果不能证明服务器拒绝申请,应先核对状态,避免重复发送。

取得 CGI137 回包后,新增可选脱敏 response_detail:native_ret 为本次业务返回码,request_opcode 为实际请求操作码(无法读取时为 null),has_response_username 表示回包用户名是否非空。添加结果、探针 last_operation 及群候选 last_result 均可查看。若微信返回 0 后插件本地校验或后处理失败,外层仍保留 native_ret:0,须同时检查 ok/status/error_code;0 不代表插件已完成全部处理。没有本次回包时不提供该详情;探针未发生操作时为 {}。详情不包含用户名、消息正文或票据。

POST /add_room_friend

用途:通过共同群中的成员原始 wxid 添加好友或发送验证申请。

已知共同群和成员原始 wxid 时,使用独立的 add_room_friend。搜索添加仍为 search_contact → add_friend,不把 wxid 塞进搜索流程,也不要求调用方提供手机号、微信号、scene 或票据。

请求参数:

{"room_id":"123456789@chatroom","wxid":"wxid_example_member","say_content":"你好,我们在同一个群里"}
  • room_id、wxid 必填,均为 1–256 字符的字符串,不含空白。只支持普通 @chatroom 群和个人联系人,暂不支持 OpenIM、公众号、群联系人或本人。
  • wxid 使用 /room_members/room_members 成员结果的 account_id(原始成员标识),也可使用已取得的原始 wxid;不能传昵称或群昵称。room_id 必须是该成员所在的共同群。
  • say_content 可省略,默认为空;仅接受字符串,会去除首尾空白,沿用 add_friend 的原生长度校验,过长拒绝发送。

插件先复用当前账号状态、群联系人和群成员列表入口,确认本人和目标都在该群;再按原生群资料链路请求 CGI182,携带目标和 fromChatRoom,按用户名匹配本次响应的群成员票据。只有取得有效联系人和票据后,才将群 ID、scene 14 和完整联系人交给 add_friend 共用的原生预检/添加执行器;普通 -44 最多一次转换为发送验证消息。调用方无需点击页面,也无需传递原始票据。列表缺失或成员关系未就绪会失败,不自动同步整个群。

HTTP 结果格式示例(身份字段为示意值):

{
  "ok":true,
  "status":"request_sent",
  "source":"room",
  "room_id":"123456789@chatroom",
  "username":"wxid_example_member",
  "is_friend":false,
  "native_ret":0,
  "stage":"send_verification",
  "contact_fetch_submitted":true,
  "has_group_member_ticket":true,
  "request_submitted":true,
  "request_cgi":137,
  "event_id":42
}

status 沿用搜索添加的 already_friend、request_sent、added、pending_sync、needs_user_action、timeout、failed;request_sent 仅表示微信确认申请已发送。已有好友不取群票据、不发添加请求。native_ret:null 表示没有可用的微信业务结果。群路径不返回 contact_ref;前置校验失败可能只有公共错误字段。

stage 增加 room_contact。contact_fetch_submitted 仅表示群资料请求获原生受理,has_group_member_ticket 仅表示本次取得的票据非空,二者都不表示好友申请成功。request_submitted 仍仅表示共享添加链路获原生受理,不包含群资料请求和独立预检查。request_cgi/event_id 为当前或最近回包诊断,CGI182 为群资料、11568 为预检查、137 为添加。发生超时、回包不完整或后处理失败时,先核对好友状态,不自动重发。

同一登录会话、同一群、同一成员、相同规范化文字,在首次请求创建起 300 秒内共享在途操作或复用最终结果(包括失败和超时);不同文字返回 ROOM_ADD_CONFLICT。最多保留 50 个群操作记录;共享在途上限 16 个。同一目标经另一群或搜索路径正在添加时返回 ADD_IN_PROGRESS。跨群、跨重启、切换账号或超过窗口不承诺去重,后端应记录操作结果,避免重复下发。整个流程单次等待,操作期限 30 秒,调用方超时建议至少 40 秒。

群相关错误包括 INVALID_PARAMETERS、ROOM_NOT_FOUND、ROOM_MEMBERS_UNAVAILABLE、NOT_IN_ROOM、CANNOT_ADD_SELF、TARGET_NOT_IN_ROOM、UNSUPPORTED_CONTACT、ROOM_CONTACT_FETCH_FAILED、ROOM_CONTACT_NOT_FOUND、GROUP_MEMBER_TICKET_MISSING、ROOM_ADD_CONFLICT;通用运行时、发送开关、切号、超时、预检及微信限制错误沿用 add_friend。GROUP_MEMBER_TICKET_MISSING 明确表示未发起好友申请,不会退回无来源 wxid 添加。

排障继续使用只读 friend_add_probe(HTTP POST /debug/friend_add_probe),可传:

{"room_id":"123456789@chatroom","wxid":"wxid_example_member"}

新增 room_runtime(群链路签名 ready/checks)、room_preflight(本地成员校验结果或明确错误)、room_candidate(cached/status/has_contact/has_group_member_ticket/last_result);last_result 为该群成员缓存的完整业务结果,仅在调用过添加后存在。last_operation 增加 source:search|room,仍为脱敏诊断。探针不联网取资料、不发送申请,不返回原始票据。首次使用先检查 add_runtime.ready 和 room_runtime.ready,再检查 room_preflight.ok;添加失败后用同一参数查看阶段与原始返回码。

共同群添加好友已由用户在微信 8.0.80 验证通过;受限/人工处理和重复请求仍按本节约定处理。

HTTP 同样保留完整业务 JSON,业务失败通常为 HTTP 200,须检查 ok/status;授权失败仍为 HTTP 403。

POST /debug/friend_add_probe

用途:只读检查主动添加链路。请求体 {}、{"contact_ref":"fc_example_ref"} 或 {"room_id":"123456789@chatroom","wxid":"wxid_example_member"};搜索及群场景输出字段和排障顺序见上节。


POST /accept_friend_request

用途:同意好友申请。

字段 类型 必填 说明
encrypt_username string ✅ 加密用户名,从好友申请事件里拿
ticket string ✅ 凭证,从好友申请事件里拿
request_id string — 好友申请的业务 ID(见下方警告)
scene int — 场景值,默认 0
say_content string — 同意时附带打招呼内容

⚠️ 重名陷阱:这里的 request_id 是好友申请本身的业务标识,和长轮询/WebSocket 命令信封上的 request_id(用于结果关联)完全是两回事,只是名字撞了。在长轮询/WebSocket 里下发这条命令时,你会同时看到两个 request_id 出现在不同层级,别搞混——信封上那层是给你的请求编号,args 里这层是微信的业务申请 ID。

成功响应:

{
  "ok": true,
  "request_id": "好友申请业务ID",
  "encrypt_username": "...",
  "ticket": "...",
  "scene": 0,
  "say_content": ""
}

POST /delete_friend

用途:删除好友。

字段 类型 必填 说明
id string ✅ 好友的 wxid

成功响应:{"ok": true, "id": "..."}

好友备注、星标和黑名单

三个入口均为 POST /set_friend_remark、POST /set_friend_star、POST /set_friend_blacklist,请求使用 application/json。

仅支持已登录账号的普通微信好友,id 必须是其真实 user_name / wxid。不支持自己、群、公众号、系统号、OpenIM 或已注销好友;已拉黑的好友仍可取消黑名单。沿用鉴权和发送开关,拒绝未知字段。

接口/命令 参数 设置 清空/取消
set_friend_remark id, remark {"id":"wxid_example","remark":"张三"} {"id":"wxid_example","remark":""}
set_friend_star id, starred {"id":"wxid_example","starred":true} {"id":"wxid_example","starred":false}
set_friend_blacklist id, blacklisted {"id":"wxid_example","blacklisted":true} {"id":"wxid_example","blacklisted":false}

remark 必须显式传入字符串,使用微信 formatter 规范化,再按微信 charLength <= 32 校验,超限拒绝;这不是通用 Unicode 字符数限制。starred / blacklisted 必须显式传入 JSON 布尔值,0/1、"false"、null、缺省均拒绝。相同目标值返回 unchanged,不再次提交原生修改。

status ok 说明
applied_locally true 原生方法返回成功,重新查询的本地值与目标一致
unchanged true 原值已等于目标;already_set=true,accepted=false、sync_requested=false
failed false 参数、账号、好友类型、写开关或 ABI 校验失败,未进入修改调用
unknown false 进入调用后返回失败、发生异常、账号变化或回读不一致,可能已有本地变化

accepted 仅代表原生 BOOL 返回成功;sync_requested 仅说明已进入原生同步调用路径,不保证入队成功。local_verified 是本地联系人回读;server_confirmed 固定 false,当前实现不等待服务器 ACK。ok=true 不保证另一台设备已同步,unknown 不宜自动重提。

响应中的 remark / starred / blacklisted 是请求目标值(备注为规范化值),不是失败后的实际值;非法或缺失字段可能使用空串/false 占位,必须结合 ok / status。联系人摘要在 getter 可读时附带 is_starred / is_blacklisted,未知则省略。原有 remark / display_name 继续可读,清空备注后显示名回退昵称。

好友设置已由用户在微信 8.0.80 验证通过;Unicode 长度限制及断网/跨设备同步仍按本节约定和微信实际状态处理。

请求与响应示例:

POST /set_friend_star
Content-Type: application/json

{"id":"wxid_example","starred":true}
{
  "ok": true,
  "id": "wxid_example",
  "starred": true,
  "accepted": true,
  "sync_requested": true,
  "already_set": false,
  "local_verified": true,
  "server_confirmed": false,
  "status": "applied_locally",
  "error": "",
  "version": "8.0.80-2"
}

业务失败也返回 HTTP 200,并保留全部状态字段;鉴权失败仍为 HTTP 403。可导入本目录 微信机器人.apifox.json(资料未收录),其中已完整收录三个好友设置接口。

列表与群成员返回字段

联系人摘要对象(items[] / members[] 的元素)

friends、friends_all、groups_all、room_members 使用相同的基础联系人字段,并按场景增加好友或群成员字段。HTTP 好友数据位于 items[],WebSocket/长轮询命令位于成功响应的 result.items[];群成员数据位于对应的 members[]。

字段 类型 出现条件 含义
account_id string 恒有 内部微信 ID(wxid);群聊时为群 ID。好友接口的 id 通常使用此值
display_name string 恒有 好友展示名依次取备注、昵称、微信 ID;群成员场景可使用群内显示名
remark string 恒有 当前账号给对方设置的备注;无备注或取不到时为空串
alias string 恒有 对方设置的微信号;未设置或取不到时为空串,与内部 wxid 分开使用
nick_name string 恒有 微信昵称(群聊时为群名);取不到时为空串
avatar_url string 恒有 头像图片地址;取不到时为空串。JSON 中的 \/ 解析后就是 /
sex int 恒有 0 未知、1 男、2 女;取不到时为 0
province string 恒有 本地资料中的省份;没有有效值时为空串
city string 恒有 本地资料中的城市;没有有效值时为空串
signature string 恒有 微信个性签名;未设置或取不到时为空串
contact_found bool 恒有 是否在本地找到联系人对象;不能据此判断对方是否删除了你
is_starred bool 可读取状态时 当前账号是否将对方设为星标;false 为未设星标,未知时省略字段
is_blacklisted bool 可读取状态时 当前账号是否将对方加入黑名单;false 为未拉黑,未知时省略字段
add_time int / null 好友列表恒有 微信资料页使用的添加时间,Unix 秒级时间戳;没有有效记录或读取失败为 null
add_time_text string / null 好友列表恒有 同一添加时间的公历文本,固定北京时间(UTC+8)、24 小时制,格式 YYYY-MM-DD HH:mm:ss;add_time=null 时同为 null
pay_name_last_char string 好友列表恒有 微信支付脱敏姓名末尾可见的一个组合字符,例如“明”;没有有效结果时为空串,不提供完整姓名
pay_name_status string 好友列表恒有 支付姓名查询状态,取值见下表;好友列表只读取缓存
is_owner bool 群成员场景,可读取时 是否群主;未知时省略字段
is_admin bool 群成员场景,可读取时 是否管理员;未知时省略字段
is_self bool 群成员场景,可读取时 是否当前登录账号;未知时省略字段

空值与省略规则:

  • 普通字符串的 "" 表示未设置或本地没有取得有效值;不能据此推断对方资料一定为空。
  • add_time 与 add_time_text 总是成对返回:有值时分别为秒级整数和 UTC+8 文本,未知时均为 null。不以 0、空串或 1970 年日期代替未知,也不使用本地添加流程时间兜底。
  • is_starred、is_blacklisted 及群成员角色字段可能整个省略。字段缺失表示未知,不能按 false 处理。

添加时间来自微信当前保存的记录,与微信资料页使用的字段一致;不承诺删除后重加时仍是终身首次添加时间。文本不随手机时区、语言或日历设置变化。两个好友查询及同名命令均无需新增请求参数。

支付姓名状态:

pay_name_status 含义
not_queried 尚未查询;姓名末字为空,不代表未实名
querying 排队或查询中,尚无最终结果
ok 已取得有效姓名末字,pay_name_last_char 非空
unavailable 微信业务响应成功,但没有可用末字;不能据此判断未实名或被单删
failed 查询失败

friends、friends_all 本身不发起支付姓名查询,需要时调用 friend_pay_name;其结果不会改变昵称、备注或 display_name。

完整好友条目示例(虚构数据,共 17 个字段):

{
  "account_id": "wxid_example",
  "display_name": "示例备注",
  "remark": "示例备注",
  "alias": "wechat_example",
  "nick_name": "示例好友",
  "avatar_url": "",
  "sex": 0,
  "province": "",
  "city": "",
  "signature": "",
  "contact_found": true,
  "is_starred": false,
  "is_blacklisted": false,
  "add_time": 1704067200,
  "add_time_text": "2024-01-01 08:00:00",
  "pay_name_last_char": "",
  "pay_name_status": "not_queried"
}

时间未知时的字段节选:

{"add_time": null, "add_time_text": null}

friends 的返回

以下为响应结构节选,数组中的 ... 表示省略内容,不能直接作为 JSON 解析:

{
  "ok": true,
  "keyword": "",
  "limit": 100,
  "offset": 0,
  "total": 256,
  "has_more": true,
  "items": [ ... ]
}
字段 类型 说明
ok bool 恒为 true
keyword string 回显你传的过滤词
limit int 回显本次页大小;缺省时按 100
offset int 回显本次偏移;缺省时按 0
total int 符合条件的总数
has_more bool 是否还有下一页
items array 联系人摘要数组

翻页方法:不断增大 offset(offset += limit),直到 has_more 为 false。


friends_all 的返回

以下为响应结构节选,数组中的 ... 表示省略内容,不能直接作为 JSON 解析:

{
  "ok": true,
  "keyword": "",
  "total": 256,
  "friend_count": 256,
  "official_account_count": 12,
  "work_account_count": 0,
  "system_account_count": 4,
  "chatroom_count": 38,
  "stranger_count": 0,
  "cached_contact_count": 310,
  "items": [ ... ]
}
字段 类型 说明
keyword string 回显过滤词
total int 本次返回的普通好友数量,等于 friend_count 和 items 长度
friend_count int 关键词过滤后的普通好友数量
official_account_count int 公众号数量
work_account_count int 企业微信联系人数量
system_account_count int 系统账号数量(如文件传输助手、微信团队)
chatroom_count int 群聊数量
stranger_count int 陌生人数量
cached_contact_count int 未经关键词过滤的原始缓存联系人条数
items array 联系人摘要数组

friends_all.items 只返回筛选后的普通好友,支付姓名字段只附带已有缓存。各类联系人计数用于说明本地通讯录构成,不表示这些联系人也会混入 items;好友数量可读取 friend_count,原始缓存联系人数量读取 cached_contact_count。


groups_all 的返回

以下为响应结构节选,数组中的 ... 表示省略内容,不能直接作为 JSON 解析:

{
  "ok": true,
  "keyword": "",
  "total": 38,
  "items": [ ... ]
}
字段 类型 说明
keyword string 回显过滤词
total int 群聊总数
items array 群聊摘要数组(字段同上,account_id 即群 ID)

groups_all 没有 has_more / limit / offset,它一次返回全部。


room_members 的返回

以下为响应结构节选,数组中的 ... 表示省略内容,不能直接作为 JSON 解析:

{
  "ok": true,
  "room_id": "50136399923@chatroom",
  "room_name": "项目群",
  "room_remark": "",
  "current_user": "wxid_self",
  "owner_user_name": "wxid_owner",
  "admin_count": 2,
  "admin_user_names": ["wxid_owner", "wxid_admin"],
  "admin_members": [ ... ],
  "self_is_owner": false,
  "self_is_admin": false,
  "member_count": 24,
  "members": [ ... ]
}
字段 类型 说明
room_id string 群 ID
room_name string 群名称
room_remark string 群备注;未设置为空串
current_user string 当前登录账号的 wxid
owner_user_name string 群主的 wxid
admin_count int 管理员数量
admin_user_names string[] 管理员 wxid 数组
admin_members array 管理员详细信息数组(结构与 members 相同)
self_is_owner bool 当前账号是否群主
self_is_admin bool 当前账号是否管理员
member_count int 群成员总数
members array 成员摘要数组

失败时的响应:{"ok": false, "error": "...", "room_id": "..."}——失败也会带上 room_id,便于定位是哪个群出错。


查询接口失败时的统一行为

friends、friends_all、groups_all、room_members 在业务失败时返回:

{ "ok": false, "error": "<原因>" }

其中 room_members 会额外带上 room_id。HTTP 状态码此时仍可能是 200——这正是 3.2 节 强调"必须同时看状态码和 ok"的原因。


10. 群聊管理

POST /groups_all

用途:一次性返回全部群聊。

字段 类型 必填 说明
keyword string — 关键词过滤

成功响应:

以下为响应结构节选,数组中的 ... 表示省略内容,不能直接作为 JSON 解析:

{
  "ok": true,
  "keyword": "",
  "total": 38,
  "items": [ ... ]
}

无分页字段,一次返回全部。


POST /room_members(别名 /debug/room_members)

用途:查询某个群的成员列表。

字段 类型 必填 说明
room_id string ✅ 群 ID

成功响应:{"ok": true, "room_id": "...", "members": [...], "admin_members": [...]} 等,详见 列表与群成员返回字段。

两个路径的区别:用 /room_members 时返回的是精简后的对外字段;用 /debug/room_members 时响应里会额外带上 path 字段和更多内部调试信息。正式对接请用 /room_members。

POST /get_chatroom_qrcode:阻塞获取指定群二维码

curl --max-time 40 --request POST 'http://192.0.2.10:19088/get_chatroom_qrcode' \
  --header 'Content-Type: application/json' \
  --data-raw '{"room_id":"example@chatroom"}'

每次调用按微信原生协议创建独立请求,通过当前登录会话的 EventService 发起取码,在同一次调用中等待微信本次响应;不返回查询中状态,不需要任务 ID。同群并发共用正在处理的请求,完成后再次调用会重新取码。最多 32 个不同群的待处理请求,约 30 秒超时,接口等待保护上限约 31 秒;调用方超时建议至少 40 秒。

唯一参数 room_id 必须是实际群 ID 字符串,例如 example@chatroom,不能传群名。当前账号须能找到该群联系人,最终权限以微信响应为准。

字段 类型 含义
room_id string 目标群 ID
status string ok / restricted / failed / timeout
qr_code_url string / null 本次响应里的二维码内容,即扫码承载的入群链接;不是 PNG 下载地址
has_qrcode bool / 0或1 是否取得 URL 或可解码图片;受限提示图也会为真,不代表可扫码入群
has_image bool / 0或1 是否含可解码图片,可能是受限提示图
image_base64 string / null 服务器返回图片经解码后统一编码的 PNG base64,不含 data URI 前缀
image_mime_type string / null 有图片时为 image/png
qrcode_status uint32 / null 微信二维码原始状态;不是 BOOL,缺失时不补 0
restricted bool / 0或1 / null 已知二维码状态是否非零;未知时为 null
footer_wording string 微信本次返回的说明,可能包含有效期或限制文字,不自行推算
wechat_ret int32 / null 微信业务原始错误码
wechat_error_message string 微信 baseResponse.errMsg.string 原文,可能为空
message_type uint32 / null 微信网络消息类型,1 视作失败
transport_error_type / transport_error_code int32 / null 微信传输错误分类及原码,保留负数
error_code string 失败或受限时的插件错误分类
request_submitted bool / 0或1 本次原生事件服务是否返回非零事件 ID,不等于服务器业务成功
request_cgi uint32 / null 本次请求 CGI:普通群 168、OpenIM 890,准备前失败为 null
event_id uint32 / null 本次已受理的原生事件 ID,仅用于诊断,无需用它轮询

status=ok 表示本次业务响应成功且取得二维码内容,不能保证扫码立即入群。restricted 对应微信非零二维码状态,业务 ok=false,error 提供中文分类说明;具体原因可能在可读文本字段或返回图片中;即使有图或 URL 也不作为普通成功处理。没有恢复具体状态枚举,不写死“1=超员、2=开启验证”。网络失败、微信 ret != 0、响应不完整和超时均返回失败信息,不返回旧缓存的码。

人数阈值由微信配置控制(静态样本默认 200,客户端判断人数达到阈值);开启管理员进群验证也不一定禁止取码,新管理方式可以扫码申请审批。因此不按人数或验证开关在本地直接拒绝,以本次微信原码与文案为准。

普通群可能只有 URL,没有服务器图片;调用方可用 qr_code_url 自行生成二维码,无需手机下载再上传。接口不会读取微信磁盘缓存,也不返回本地文件路径。微信保存的完整分享卡片还会组合群头像、群名和有效期提示,本接口不拼装该卡片。

OpenIM 按微信原生群类型判断分流至 CGI890;该分支可能只有图片,没有 URL,也没有二维码状态,此时 qrcode_status、restricted 为 null。仍校验本次原始业务响应,不能依赖原生固定为 0 的完成通知。

常见 error_code:INVALID_ROOM_ID、ACCOUNT_UNAVAILABLE、ACCOUNT_CHANGED、ROOM_NOT_FOUND、NATIVE_API_UNAVAILABLE、TOO_MANY_REQUESTS、REQUEST_NOT_STARTED、NATIVE_REQUEST_FAILED、RESPONSE_INVALID、WECHAT_REQUEST_FAILED、RESPONSE_INCOMPLETE、QRCODE_RESTRICTED、QRCODE_TIMEOUT。REQUEST_NOT_STARTED 仅在原生事件服务返回事件 ID 为 0 时使用,不能据此推断群人数或验证限制。request_submitted=true 仅表示微信事件服务已受理,不代表服务器成功;若之后返回 QRCODE_TIMEOUT,表示尚未取得本次最终响应。

中文原因取自微信可读字段:footer_wording 和 wechat_error_message。受限时优先使用非空 footer_wording 作为 error;没有该文案时返回通用中文“微信返回二维码受限状态”,并原样保留 wechat_error_message。微信可能将具体原因直接写在返回图片里,两个文本字段均为空;本接口不做图片文字识别,也不根据 qrcode_status=1 等原始值硬编码具体原因。

用户提供的普通群真机响应已确认:请求受理并收到 wechat_ret=0,qrcode_status=1,返回 PNG,qr_code_url=null,footer_wording、wechat_error_message 均为空;人工查看图片文字为“该群已开启进群验证,只可通过邀请进群”。这只说明该次图片的含义,不是所有状态值 1 的固定映射。

has_qrcode、has_image、restricted、request_submitted 可能序列化为布尔值或数字 0/1,restricted 还可能为 null。has_image=1、has_qrcode=1 只表示有返回内容,不保证图片是可用的入群码。业务是否成功应先检查 ok 和 status。

群二维码功能已由用户在微信 8.0.80 验证通过;取码成功不保证立即入群,实际扫码仍受群设置及微信返回限制。上述受限图片记录不构成固定状态码映射,也不能据此扩大 OpenIM 支持范围。

受限响应示例(节选;群 ID 和事件 ID 为占位值,实际 image_base64 是 PNG Base64 字符串,本文省略图片内容):

{
  "ok": false,
  "room_id": "example@chatroom",
  "status": "restricted",
  "qr_code_url": null,
  "has_qrcode": 1,
  "has_image": 1,
  "image_mime_type": "image/png",
  "qrcode_status": 1,
  "restricted": 1,
  "footer_wording": "",
  "wechat_ret": 0,
  "wechat_error_message": "",
  "message_type": 0,
  "transport_error_type": 0,
  "transport_error_code": 0,
  "request_submitted": 1,
  "request_cgi": 168,
  "event_id": 42,
  "error_code": "QRCODE_RESTRICTED",
  "error": "微信返回二维码受限状态"
}

成功示例(链接为占位值):

{
  "ok": true,
  "room_id": "example@chatroom",
  "status": "ok",
  "qr_code_url": "https://weixin.qq.com/g/example",
  "has_qrcode": true,
  "has_image": false,
  "image_base64": null,
  "image_mime_type": null,
  "qrcode_status": 0,
  "restricted": false,
  "footer_wording": "",
  "wechat_ret": 0,
  "wechat_error_message": "",
  "message_type": 0,
  "transport_error_type": 0,
  "transport_error_code": 0,
  "request_submitted": true,
  "request_cgi": 168,
  "event_id": 42
}

查询结果、业务失败和受限结果均为 HTTP 200,须检查 ok、status;失败说明在顶层 error,授权失败仍为 HTTP 403。HTTP 等待只占用当前连接,不阻塞微信主线程或其他业务接口。

创建群聊、直接加人和发送入群邀请

入口为 POST /create_group、POST /add_group_member、POST /invite_group_member;邀请兼容 POST /group/invite_member。沿用本篇本地HTTP地址和JSON请求体设置;仅检查插件自身授权状态,不校验请求Token,也不要求调用方添加鉴权Token。

三项操作分别表示创建普通微信群、尝试直接加入群成员、发送需要对方接受的入群邀请。插件不按“40 人”硬切换,也不把添加失败自动转成发送邀请;是否可直接加入取决于微信服务端和群设置。所有结果均须查看业务状态,原生方法返回成功不等于成员已经入群。

验证范围:已有用户确认的 HTTP 真机记录,覆盖两位好友建群、直接添加已在群成员、移出后重新添加、邀请已在群成员和移出后发送邀请。邀请成功只确认发送。用户现已确认建群、添加与邀请成员功能在微信 8.0.80 验证通过。是否可直接加人仍由微信与群设置决定,审批、部分成功、超时及账号切换按本节状态处理。request_submitted 为 boolean。

使用范围与完整参数

必须已登录并开启插件写入/发送开关。待操作对象必须是当前账号的普通微信好友,传真实内部 ID;不支持昵称、完整微信号 alias、企业微信用户或群 ID 充当成员。添加和邀请只支持普通 @chatroom 群,并须能从当前群成员快照确认本人在群;无须由插件预设“只有群主能加人”,实际权限和人数限制由微信返回。

参数 类型 创建 create_group 添加 add_group_member 邀请 invite_group_member
request_id string 必填 必填 强烈建议传;具体位置与兼容默认值见本节通道说明
member_id string 与 member_ids 二选一,但单个其他好友无法达到首版建群最低人数 与 member_ids 二选一 单人邀请;与旧字段合并规则见下文
member_ids string[] 非空数组;去重并排除本人后至少 2 位其他好友 非空数组;与 member_id 二选一 非空数组,支持批量
room_id string 不接受 必填 必填,兼容群 ID 别名见下文
reason string 不接受 选填,默认空串,表示入群申请说明 不接受

request_id 去除首尾空白后须为 1–128 个字符;成员和群 ID 也去除首尾空白,内部不能含空白。成员去重后按 ID 排序。创建时自动排除本人;至少两位其他好友是本接口首版支持范围,不是对微信服务端所有建群方式最低人数的断言。创建不接受 topic/群名,群创建后如需命名,使用已有 set_group_name,其结果独立判断。

添加/邀请先排除本机快照中已在群的成员,只向微信提交剩余普通好友;已在群者放入 already_in_room_member_ids。全部已在群时返回 already_in_room,不提交新请求;仅本机快照确认,server_confirmed:false。若任一待提交成员不是普通好友,整次请求在提交前失败,不偷偷跳过该人。

邀请保留单值别名 user_name/wxid、数组别名 user_names/wxids;可以和 member_id/member_ids 同时提供,合并、校验、去重排序。群 ID 可用 chatroom_id/group_id/to_user_name,同时传多个群字段时规范化后须一致。创建和添加不支持这些旧别名,也不允许同时传多个成员字段。未列出的参数直接拒绝,不静默忽略;null 不能代替字符串或数组。

返回字段与成功判断

下表是完整业务字段;ok/error 所在位置见本节通道说明。初始失败可能尚未解析到成员或群 ID,因此对应字段为空。message、error、error_code 和 replayed 为按情况出现的字段,其余业务字段默认存在。

字段 类型/默认值 含义
ok boolean,false 创建时表示已确认建成群;添加时表示目标均已加入或已在群;邀请时表示本批邀请已发送,或目标本来全已在群
status string,failed 当前业务状态,见下表
mode string create/add/invite
request_id string,空串 本次规范化后的业务请求 ID,须保存用于查询和重试去重
room_id string,空串 添加/邀请的目标群;创建成功后为微信实际返回的新群 ID
member_ids、member_count string[]/integer,[]/0 去重排序后的目标成员和数量;创建时已排除本人
submitted_member_ids string[],[] 筛选出的本次原生目标成员;是否实际提交还须看 request_submitted
already_in_room_member_ids string[],[] 提交前本机快照已确认在群的目标成员
accepted boolean,false 微信原生方法的布尔返回值,不代表发出、成功或成员已入群
request_submitted boolean,false 已取得本次原生事件 ID;不代表微信服务端接受
response_received boolean,false 已收到与本请求匹配的原生回包;内容仍可能不完整
server_confirmed boolean,false 本动作已由微信服务端确认成功:创建得到有效新群ID、添加确认所有目标已入群、邀请批次发送成功;拒绝、需邀请、待审批或全部原已在群时为false
request_cgi integer/null,null 本次原生请求类型:创建119、添加120、邀请610;尚未提交时可能为 null
event_id integer/null,null 本次原生事件编号,用于诊断;不是事件拉取编号或单独查询入口
wechat_ret integer/null,null 微信业务返回码,不能把缺失值按0处理
wechat_error_message string,空串 微信原始错误说明
message_type、transport_error_type、transport_error_code integer/null,null 原生消息状态与传输错误字段
created boolean,false 是否确认本次创建了群;其他两种操作为false
all_members_added boolean,false 是否确认所有目标均已加入或已在群;发出邀请不会因此变成true
member_results object[],[] 创建/添加的逐成员结果;每项有 member_id:string、status:string、native_status:integer/null
invite_required_member_ids string[],[] 完整回包确认可进一步发送邀请的成员;由调用方显式发起新邀请操作
replayed boolean,可省略 为true时表示读取了同ID的已登记操作,没有重新提交原生请求
message string,可省略 成功后的补充说明
error_code、error string,可省略 失败、需后续处理或结果未知时的错误分类与中文说明
status ok 如何处理
created true 群已创建,读取新 room_id;仍须看 all_members_added 与逐成员结果,不能因部分成员失败再次建群
added true 所有目标都已加入或本来就在群
invitation_sent true 仅确认本批邀请发送,对方接受后才会入群;不提供伪造的逐人成功结果
already_in_room true 全部目标在提交前已存在于本机群快照,没有新请求
requires_invitation false 直接加人未完成;只对 invite_required_member_ids 按业务需要显式调用邀请,并用新的业务ID
requires_verification false 成员需要好友验证,先处理好友关系
approval_pending false 已进入群主/管理员确认流程,等待确认;尚未加入
partial false 添加批次有多种结果,包括需验证等已知结果与unknown混合;逐人查看 member_results,含unknown时仍保留同群占用,不自动重复整批
processing false 同ID操作仍在等待回包,稍后以相同参数、同ID读取
failed false 参数、环境或业务失败;结合是否提交、错误码和微信原始提示处理
unknown false 无法确认是否生效;以同ID读取迟到结果,必要时核实真实群状态,不自动重发

逐成员 status 可能为 added、already_in_room、requires_invitation、requires_verification、approval_pending、failed、unknown。原生 native_status=0 不能独立判断加入成功,必须与总返回码共同解释:例如添加回包 wechat_ret=-2012 表示需要邀请的分支,-2028 可表示等待群主/管理员确认。wechat_ret=-2012 下 native_status=3 表示拒绝加入,逐成员为failed;状态10含义尚不能确认,保留unknown。创建成功但成员信息不完整时仍返回 created,相关成员为unknown、all_members_added:false。正常邀请回包只确认批次发送,member_results:[];全部目标已在群而未发送时可返回逐人的 already_in_room。

错误、等待、去重与重试

error_code 含义与处理
INVALID_PARAMETERS、INVALID_REQUEST_ID、INVALID_ROOM_ID、INVALID_MEMBER_IDS、INVALID_REASON、TOO_FEW_MEMBERS 参数不符合本节契约,未启动业务请求
REQUEST_ID_CONFLICT 同ID已经对应其他规范化参数,或命令args与信封ID冲突;不得用改参数方式查询原操作
ACCOUNT_UNAVAILABLE、WRITE_DISABLED、ROOM_STATE_UNAVAILABLE、FRIEND_REQUIRED 登录/开关/群快照/好友条件不足,未发起新请求
UNSUPPORTED_ROOM 无法确认目标是普通微信群,或属于不支持的企业互通/升级群,未发起新请求
OPERATION_BUSY 同群,或当前账号的建群操作,存在等待中或未解决的未知结果;先处理原操作
REQUEST_RECORD_LIMIT 当前登录上下文已登记512项操作,新操作被拒绝;已有ID仍可查询,不淘汰旧记录后冒险重发
NATIVE_API_UNAVAILABLE、INVALID_CALL_THREAD 原生接口不兼容或调用线程错误;保留结果用于排查
REQUEST_NOT_CONFIRMED、NATIVE_REQUEST_FAILED 原生调用或提交确认异常;检查 status、accepted、request_submitted,可能未知,不自动重试
WECHAT_REQUEST_REJECTED 微信明确拒绝本次业务,查看 wechat_ret 与原始说明
MEMBERS_NOT_ALL_ADDED、MEMBER_RESPONSE_INCOMPLETE 添加未确认所有目标入群,逐人处理;成员信息不完整不能当作全部成功
RESPONSE_MISMATCH、RESPONSE_INCOMPLETE、RESPONSE_INVALID、ROOM_ID_MISSING 回包错配/缺失/异常,或建群成功码缺少群ID,结果未知
OPERATION_TIMEOUT、ACCOUNT_CHANGED 等待超时或登录上下文改变,核实原业务结果

服务等待真实回包约30秒,外层等待保护约31秒;客户端建议至少40秒,iOS挂起、通信排队或断线可能更久,不能把连接超时直接当业务失败。该能力不新增完成事件或单独查询接口;迟到回包会更新当前进程内记录,使用原接口/命令、原ID和相同规范化参数读取即可。

三种接入方式共用当前账号登录上下文内的操作记录。登记后相同ID、相同操作/群/去重排序成员/reason只读取记录,不再次提交;在途返回processing,结束后返回当前结果并带 replayed:true。同ID不同参数返回冲突。参数或环境校验阶段尚未登记的失败不等于已建立去重记录。新业务必须用新ID;同ID只能查询/重放原业务,不用于强制重新执行。

最多保留512项已登记操作,达到上限拒绝新操作,不按最近条目淘汰。添加操作只要仍有待添加成员结果为 unknown,即使回包字段齐全或顶层为 partial,也继续占用同群操作槽位,并等待迟到回包;已知结果与未知结果混合时逐人处理,不能据此重发整批。唯一可继续的同群操作是显式邀请:新邀请的全部目标必须属于该未完成添加记录的 invite_required_member_ids 已确认名单,并使用新的业务ID;不在名单内的邀请和其他添加仍返回OPERATION_BUSY,原添加记录继续等待。只有成员结果完整且均已明确,才解除该添加占用。邀请本身结果未知也保留同群占用,上述例外不会绕过其他未完成的邀请。建群尚未取得有效新群ID时的未知结果会占用当前账号建群槽位;已取得有效新群ID则返回 created 并解除建群占用,成员部分未知也不能重复创建原业务群。记录仅在当前微信进程和登录上下文内有效,进程重启、重新登录或服务上下文变化(含群服务重新初始化)后不保证去重;不要通过重启或换ID绕过未知结果。后端应保存业务ID及收到的结果,跨重启先核实群状态,再由业务决定下一步。

本模式封装与调用示例

参数直接放JSON请求体。新建群和添加必须提供 request_id;旧邀请接口缺省时自动生成并在结果中返回,兼容调用虽可继续使用,但无法用省略ID的重复请求去重,建议调用方主动提供并保存ID。

三个业务入口通过通用解析和鉴权后,均返回HTTP200并保留完整业务结果;ok/status 位于响应顶层,统一出口可能附带 version。HTTP200不表示已建群/已入群。非法JSON或非对象JSON会被解析层视为空字典,并返回HTTP200参数失败;本接口不另报JSON语法400。未授权仍为403,路径/方法不匹配为404,请求接收超时或过大分别为408/413。写入开关关闭的新请求为HTTP200的WRITE_DISABLED。旧邀请接口的业务失败由原来的HTTP400改为HTTP200完整结果,旧调用方应改为检查顶层 ok、status、error_code。

POST /create_group:

{
  "request_id": "req-create-001",
  "member_ids": [
    "wxid_member_a",
    "wxid_member_b"
  ]
}

POST /add_group_member:

{
  "request_id": "req-add-001",
  "room_id": "123456789@chatroom",
  "member_id": "wxid_member_a",
  "reason": ""
}

POST /invite_group_member:

{
  "request_id": "req-invite-001",
  "room_id": "123456789@chatroom",
  "member_ids": [
    "wxid_member_a"
  ]
}

建群成功示例(字段格式示例,不是真机记录):

{
  "ok": true,
  "status": "created",
  "mode": "create",
  "request_id": "req-create-001",
  "room_id": "123456789@chatroom",
  "member_ids": [
    "wxid_member_a",
    "wxid_member_b"
  ],
  "member_count": 2,
  "submitted_member_ids": [
    "wxid_member_a",
    "wxid_member_b"
  ],
  "already_in_room_member_ids": [],
  "accepted": true,
  "request_submitted": true,
  "response_received": true,
  "server_confirmed": true,
  "request_cgi": 119,
  "event_id": 42,
  "wechat_ret": 0,
  "wechat_error_message": "",
  "message_type": 0,
  "transport_error_type": 0,
  "transport_error_code": 0,
  "created": true,
  "all_members_added": true,
  "member_results": [
    {
      "member_id": "wxid_member_a",
      "status": "added",
      "native_status": 0
    },
    {
      "member_id": "wxid_member_b",
      "status": "added",
      "native_status": 0
    }
  ],
  "invite_required_member_ids": []
}

直接添加需要改走邀请示例(字段格式示例,不是真机记录):

{
  "ok": false,
  "status": "requires_invitation",
  "mode": "add",
  "request_id": "req-add-001",
  "room_id": "123456789@chatroom",
  "member_ids": [
    "wxid_member_a"
  ],
  "member_count": 1,
  "submitted_member_ids": [
    "wxid_member_a"
  ],
  "already_in_room_member_ids": [],
  "accepted": true,
  "request_submitted": true,
  "response_received": true,
  "server_confirmed": false,
  "request_cgi": 120,
  "event_id": 42,
  "wechat_ret": -2012,
  "wechat_error_message": "",
  "message_type": 0,
  "transport_error_type": 0,
  "transport_error_code": 0,
  "created": false,
  "all_members_added": false,
  "member_results": [
    {
      "member_id": "wxid_member_a",
      "status": "requires_invitation",
      "native_status": 0
    }
  ],
  "invite_required_member_ids": [
    "wxid_member_a"
  ],
  "error_code": "MEMBERS_NOT_ALL_ADDED",
  "error": "成员未全部确认加入,请查看 member_results;需要邀请时显式调用 invite_group_member"
}

邀请批次已发送示例(字段格式示例,不是真机记录):

{
  "ok": true,
  "status": "invitation_sent",
  "mode": "invite",
  "request_id": "req-invite-001",
  "room_id": "123456789@chatroom",
  "member_ids": [
    "wxid_member_a"
  ],
  "member_count": 1,
  "submitted_member_ids": [
    "wxid_member_a"
  ],
  "already_in_room_member_ids": [],
  "accepted": true,
  "request_submitted": true,
  "response_received": true,
  "server_confirmed": true,
  "request_cgi": 610,
  "event_id": 42,
  "wechat_ret": 0,
  "wechat_error_message": "",
  "message_type": 0,
  "transport_error_type": 0,
  "transport_error_code": 0,
  "created": false,
  "all_members_added": false,
  "member_results": [],
  "invite_required_member_ids": []
}

已提交但超时未知示例(字段格式示例,不是真机记录):

{
  "ok": false,
  "status": "unknown",
  "mode": "add",
  "request_id": "req-add-001",
  "room_id": "123456789@chatroom",
  "member_ids": [
    "wxid_member_a"
  ],
  "member_count": 1,
  "submitted_member_ids": [
    "wxid_member_a"
  ],
  "already_in_room_member_ids": [],
  "accepted": true,
  "request_submitted": true,
  "response_received": false,
  "server_confirmed": false,
  "request_cgi": 120,
  "event_id": 42,
  "wechat_ret": null,
  "wechat_error_message": "",
  "message_type": null,
  "transport_error_type": null,
  "transport_error_code": null,
  "created": false,
  "all_members_added": false,
  "member_results": [],
  "invite_required_member_ids": [],
  "error_code": "OPERATION_TIMEOUT",
  "error": "等待微信回包超时,可能已生效;请用相同 request_id 查询,勿换 ID 重发"
}

POST /kick_group_member(别名 /kick_group_members)

用途:踢出群成员。

字段 类型 必填 说明
room_id string ✅ 群 ID
member_id string — 单个
member_ids string[] — 批量
wxid / wxids — — 上面两个的别名

member_id 与 member_ids 可同时传,自动合并去重。至少要有一个被踢对象,否则业务会失败。

成功响应:{"ok": true, "room_id": "...", "member_ids": [...], "member_count": 2}

失败响应:400,响应体带 room_id 和 member_ids 便于你定位。


POST /set_group_self_nickname(别名:POST /rename_group、POST /set_group_nickname)

用途:修改当前账号在该群里的群昵称(等同微信里「我在本群的昵称」)。修改整个群聊的名称请使用下方的 POST /set_group_name。

字段 类型 必填 说明
room_id string ✅ 群 ID
new_name string — 新的群昵称。允许空串:传 "" 表示清空群昵称、恢复默认(即显示微信昵称)。字段整体缺失才会报参数错误
nickname / room_name / group_name string — new_name 的别名(旧字段名,保留兼容)

成功响应:{"ok": true, "room_id": "...", "new_name": "...", "clears_group_nickname": false}

清空时 new_name 回显为 ""、clears_group_nickname 为 true:

curl -X POST 'http://127.0.0.1:19088/set_group_self_nickname' \
  -H 'Content-Type: application/json' \
  -d '{"room_id":"123456@chatroom","new_name":""}'

失败响应:400 + new_name is required (pass an empty string to clear your group nickname)、room contact not found 等。


POST /set_group_name

用途:修改整个群聊的名称。此接口与 rename_group / set_group_self_nickname 语义不同。

字段 类型 必填 说明
room_id string ✅ 以 @chatroom 结尾的群 ID
new_name string ✅ 新群名;去除首尾空白后必须非空,不能用空串清空群名

受插件发送开关控制。调用示例(将 <手机IP> 和群 ID 换成实际值):

curl -X POST 'http://<手机IP>:19088/set_group_name' \
  -H 'Content-Type: application/json' \
  -d '{"room_id":"123456@chatroom","new_name":"新的群聊名称"}'

成功响应示例:

{
  "ok": true,
  "room_id": "123456@chatroom",
  "new_name": "新的群聊名称",
  "accepted": true,
  "local_verified": true,
  "already_named": false,
  "local_name": "新的群聊名称"
}

accepted 只表示微信底层接受调用;local_verified 表示本机群联系人的 nick_name 已读回目标值。底层接受后,本地读回可能尚未完成,因此 ok: true 时 local_verified 也可能是 false。如果本地群名原本就等于目标值,不会重复提交,返回 ok: true、already_named: true、accepted: false、local_verified: true。以上结果都不代表其他成员端已经同步。

失败响应:HTTP 400、ok: false 和中文 error;包括群 ID 缺失或格式不对、群名为空、服务或 selector 不可用、签名不受支持、底层拒绝等。

只读探针:POST /debug/set_group_name_probe,请求体只需 {"room_id":"123456@chatroom"}。检查 group_manager_found、selector_available、signature_supported、set_group_name_ready 等字段,不执行修改。探针响应的 HTTP 状态可能是 200,仍应检查响应体里的 ok 和 set_group_name_ready。


POST /get_group_notice

用途:读取微信当前保存在本机的群公告。请求体只需 {"room_id":"123456@chatroom"},room_id 必须是以 @chatroom 结尾的字符串。接口只读本地缓存,不发起下载,也不修改公告。

curl -X POST 'http://<手机IP>:19088/get_group_notice' \
  -H 'Content-Type: application/json' \
  -d '{"room_id":"123456@chatroom"}'

读到完整公告时的响应示例:

{
  "ok": true,
  "room_id": "123456@chatroom",
  "cached_notice_found": true,
  "summary": "微信提供的文本摘要",
  "html": "<p>公告正文</p>",
  "html_cached": true
}

summary 来自微信公告项的文本摘要,可能省略格式或内容,不能当作完整正文;html 是本地 .htm 文件的原始 UTF-8 内容,保留格式。html_cached: true 表示已成功读取该文件。正文文件未缓存或无法读取时,html 为 null、html_cached 为 false,此时仍可能有 summary。

本地未读到公告项时,接口返回 ok: true、cached_notice_found: false、summary: null、html: null、html_cached: false。这不等于群里没有公告;缓存也可能不是最新内容。参数或运行时方法不受支持时返回 HTTP 400、ok: false 和 error。

邀请入群:查询、静默接受与探针

用户已确认微信 8.0.80 的邀请查询与接受入群功能验证通过。收到普通私聊邀请链接卡片后,插件从原消息取得 URL、发送方和消息上下文,经微信原生 A8Key 鉴权调用官方邀请详情/接受协议。全程不创建网页、不点击、不执行网页脚本。已有 HTTP 查询及用户提供的接受成功回包,验证范围见本节末尾。查询时 roomInfo.roomName 可缺省,目标群 ID 可在接受成功后才取得。

HTTP POST 路径 长轮询 / WebSocket 命令 行为
/get_group_invitation get_group_invitation 只查详情和限制,不接受
/accept_group_invitation accept_group_invitation 内部重新查询,满足条件才提交接受,无需先调用查询
/debug/group_invitation_probe group_invitation_probe 只读探针,stage=context/auth/info,默认 info

业务请求统一为:

{"message_id":"123456789012345678"}

message_id 取收到卡片事件的 body.message_id,必须是正整数十进制字符串(最多 20 位且不超过 uint64,无前导零)。不接受 JSON 数字,以免大整数丢精度。不需要 invite_url、chat_id、room_id、账号凭据或 ticket。账号选择沿用既有设备/账号通道;本地复核消息属于当前登录账号。回调里的 chat_id 是来源会话,私聊的 room_id 为空,不是邀请目标群。群名等来自服务器详情;目标群 ID 在查询时可为空,接受成功后从提交回包取得。

仅处理当前账号收到的普通私聊 49/5 卡片及 support.weixin.qq.com/cgi-bin/mmsupport-bin/addchatroombyinvite 邀请。 鉴权后的地址允许微信内置的 7 个 support 域名(support/szsupport/mlsupport/hksupport.weixin.qq.com、support/sgsupport/ussupport.wechat.com),仍严格检查 HTTPS、原路径、原 ticket、端口和凭据;详情/接受请求及 Origin 使用本次鉴权域名,不跟随重定向。原消息必须仍在近期缓存(当前最多 200 条),否则返回 MESSAGE_CONTEXT_NOT_FOUND,需重新取得一条新邀请。切换账号或登录上下文时停止操作。微信被系统挂起或进程结束时不能保证后台执行;“静默”指进程有运行时间时无界面地执行协议。

HTTP 需要有效插件授权;接受接口在真正提交前复核现有 sendEnabled(当前跟随插件总开关)。查询和探针沿用 HTTP 读取接口约定,不单独受发送判断约束。命令通道三项均沿用插件启用与授权检查。

结果判定

status ok 含义
ready true 查询成功,本次条件允许接受;不承诺后续提交必成功
restricted true 查询成功但不允许接受,读取 restriction_code / warning
already_joined true 本次服务器详情确认已经在群,不提交接受
accepted true 微信明确接受成功并取得有效群 ID,已有群 ID 时核对一致;后续详情尚未确认成员状态
joined true 微信接受成功,且本次后续服务器详情确认在同一群
unknown false 已开始提交,但断网、坏响应或账号变化导致无法确认结果;先查状态
failed false 前置条件失败,或微信明确拒绝
context_ready / authenticated true 仅供对应阶段探针,分别表示上下文检查通过 / 取得合法鉴权结果

ticket_used=true 单独不能证明当前还在群。openurl、额外交互或不支持的 A8Key action 会明确受限/失败。不会转到页面继续操作。查询阶段允许服务器暂不返回群 ID,仍可返回群名、人数和是否可接受;接受成功必须取得有效群 ID。后续成员核实按同一 ticket 的本次服务器详情判断,若返回群 ID 则必须匹配。旧本地群联系人或成员缓存不作为本次在群证据。

查询响应示例(依据已有真机查询结果,消息 ID 与群名已替换;查询时群 ID 缺省):

{"ok":true,"status":"ready","message_id":"123456789012345678","room_id":"","room_name":"示例群","member_count":198,"can_accept":true,"in_chatroom":false,"ticket_used":false,"restriction_code":"","warning":"为维护微信平台绿色网络环境,请勿在群内传播违法违规内容。","request_submitted":false,"membership_verified":false,"wechat_ret":0,"a8key_action":6,"wechat_err_code":0,"wechat_error_type":0,"http_status":200,"stage":"info","error_code":"","error":"","elapsed_ms":1417,"version":"8.0.80-2"}

接受响应主要看 status、request_submitted、membership_verified。request_submitted=true 只表示本次或此前同票据的接受请求已开始,不能证明服务器已接收;accepted 不等于已确认在群。接受操作的 can_accept 固定为 false,避免把已处理结果再次当作可提交邀请。

接受并核实入群成功示例(依据用户提供的真机回包,消息 ID、群名与群 ID 已替换;未独立检查手机界面):

{
  "ok": true,
  "status": "joined",
  "message_id": "123456789012345678",
  "room_id": "123456789@chatroom",
  "room_name": "示例群",
  "member_count": 198,
  "can_accept": false,
  "in_chatroom": true,
  "ticket_used": false,
  "restriction_code": "",
  "warning": "为维护微信平台绿色网络环境,请勿在群内传播违法违规内容。",
  "request_submitted": true,
  "membership_verified": true,
  "wechat_ret": 0,
  "a8key_action": 6,
  "wechat_err_code": 0,
  "wechat_error_type": 0,
  "http_status": 201,
  "stage": "verify",
  "error_code": "",
  "error": "",
  "elapsed_ms": 3876,
  "version": "8.0.80-2",
  "verification_http_status": 200,
  "verification_err_code": 0,
  "verification_error_type": 0
}

字段来源与快照语义

接受返回整合了接受前详情、接受 POST 和接受后核实三次请求:

  • room_name、member_count、ticket_used、warning 保留接受前详情快照;核实阶段不刷新这些字段。因此成功回包中 ticket_used=false、member_count=198 仍可与 status=joined 同时出现,不能据此判断票据仍可用或入群后人数仍为 198。
  • room_id 在接受成功时从 POST 回包取得;membership_verified 与 in_chatroom=true 表示后续同一票据的服务器详情已确认在群。verification_* 只记录这次核实请求,不覆盖接受 POST 的状态码。
  • warning 来自微信详情的 data.antispamwarning,为空时取 data.securitytips,再隐藏其中的凭据和链接。当前返回没有记录具体采用了哪一个源字段。这条“为维护微信平台绿色网络环境,请勿在群内传播违法违规内容。”是微信返回的普通提醒;仅有该文案不表示违规、受限或失败,限制看 status/restriction_code。

后端判断已确认在群,使用 ok=true、status 为 joined 或 already_joined,并且 membership_verified=true。request_submitted=true 仅说明开始过提交;accepted 表示微信已确认接受但成员核实尚未成功,应查询详情确认,不能自动重提。接受操作结束时 can_accept 固定为 false,表示该操作结果不再作为可接受邀请,不能把它解释成本次接受被拒绝。

实测 wechat_ret=0 表示 A8Key 鉴权成功,a8key_action=6 是原生 URL 处理分支编号。接受回包的 http_status=201 是微信接受 POST 的成功 HTTP 状态;再结合 wechat_err_code=0/wechat_error_type=0 和有效群 ID 判断接受成功。verification_http_status=200 与核实双零业务码来自随后的详情 GET,成员是否核实仍看 membership_verified。手机本地 HTTP 接口的响应状态仍是 200;不能把 JSON 内的 http_status 当作本地接口状态。

字段 类型与约定
ok, status, error_code, error 业务成败、状态、机器错误码、中文说明;成功错误字段为空串
message_id 原消息 ID 字符串
room_id, room_name 群名来自详情;群 ID 在查询时可能为空,接受成功后从提交回包取得;未知为空串
member_count 非负整数或 null;接受结果保留接受前详情人数,不是入群后实时人数
can_accept 查询是否允许接受;不能作为跨请求授权凭证;接受操作结束时固定 false
in_chatroom 布尔或 null;详情中的在群状态;接受后核实成功更新为 true
ticket_used 布尔或 null;接受结果保留接受前详情的票据状态;单独 true 也不能证明当前在群
restriction_code 限制分类,未受限为空串;取值见下方限制码
warning 微信详情 antispamwarning 优先、securitytips 兜底,脱敏后返回;接受结果保留接受前快照;普通提醒不等于受限
request_submitted, membership_verified 是否开始过接受提交、本次是否由服务器确认在群
wechat_ret 原生 A8Key baseResponse.ret,0 表示鉴权无业务错误,未到达时 null
a8key_action 原生 actionCode 分支号,当前允许 0/2/6 继续校验目标地址及密钥;实测为 6,未到达时 null
wechat_err_code, wechat_error_type 最近详情/接受 POST 的顶层 errCode、data.errorType,双零表示无业务错误;未取得为 null;不被核实请求覆盖
http_status 微信详情/接受 POST 的 HTTP 状态,接受成功实测 201;未知为 null,未取得响应时可为 0;不是手机本地 API 的 HTTP 状态
verification_err_code, verification_error_type, verification_http_status 可选;提交成功后成员核实请求的结果,不覆盖接受结果
stage context/auth/info/submit/verify,最后到达的阶段
elapsed_ms 可选;整个操作从创建到结束的总耗时,毫秒,含鉴权、详情、提交和核实中已执行的阶段
version 手机 HTTP 出口附加的 WeBridge 插件完整版本,例如 8.0.80-2,包含 deb 构建号;不是原生微信版本;本功能 WS/轮询命令结果不附加此字段
replayed 可选;true 表示此前提交过,本次只查不再 POST
diagnostics 仅探针在创建操作后返回;早期参数/缓存失败可能没有

错误码包括 INVALID_ARGUMENT、INVALID_CALL_THREAD、NOT_LOGGED_IN、ACCOUNT_CHANGED、MESSAGE_CONTEXT_NOT_FOUND、MESSAGE_CONTEXT_MISMATCH、NATIVE_UNAVAILABLE、NATIVE_EXCEPTION、A8KEY_FAILED、A8KEY_TIMEOUT、RESPONSE_INVALID、INVITATION_TIMEOUT、INVITATION_EXPIRED、INVITATION_INVALID、WECHAT_REJECTED、SEND_DISABLED、BUSY、INVITATION_LIMIT、RESULT_UNKNOWN。限制码为 INVITATION_USED、INVITATION_RESTRICTED、UNSUPPORTED_INVITATION_FLOW,接受受限时也作为错误码。

去重、超时与重试

同账号登录上下文、同票据、同操作及探针阶段的并发请求合并等待;创建操作上限 16。接受提交前登记内存记录,同一票据以后调用接受会重新查询、不重复 POST;明确拒绝可移除提交记录。提交记录当前最多 64,满时拒绝新提交,避免淘汰未知记录导致误重试。账号/会话变化或进程重启后记录不保留,不保证跨重启幂等;后端也应按账号和原消息记录已提交/未知结果,重启后先查询,不自动重发接受。

鉴权等待约 18 秒,单次 HTTP 最多 12 秒,总操作约 55 秒。调用方等待建议 75 秒。HTTP 业务结果(含失败)均返回 200 并保留完整业务 JSON;授权拦截等前置层仍沿用原错误状态,不能仅判断 HTTP 状态。不要因 30 秒内没有业务结果就自动重新提交接受操作。

只读 HTTP 探针与真机测试

统一 POST /debug/group_invitation_probe:

{"message_id":"123456789012345678","stage":"context"}
  1. context:检查原消息、当前账号、原生类和 ABI,不按固定微信版本号拦截,不调用 A8Key 或业务 HTTP。
  2. auth:在前述基础上调用原生鉴权并核对 fullUrl、ticket、exportkey,不请求邀请详情。
  3. info(默认):完成鉴权并 GET 详情,不 POST 接受。三阶段 request_submitted 均为 false。

诊断含 native_ready、native_signatures、wechat_version、message_context_found、message_type、app_msg_type、a8key_scene、a8key_opcode、callback_received;收到回调后可有 event_id、cgi、a8key_message、transport_error_type/code、exportkey_present、full_url_allowed、full_url_same_host/path/ticket、full_url_https、full_url_has_fragment、full_url_host(仅 hostname)、full_url_host_allowed、full_url_port(未显式设置时 null)、full_url_has_credentials、a8key_header_names;HTTP 后可有 business_http_host(应与鉴权 hostname 相同)、http_response_mime、last_response_bytes、network_error_code、http_json_object、data_object、room_info_object 及固定业务字段名称列表 invitation_fields。业务解析后还有 response_field_types(固定字段的 JSON 类型,含 missing/null)、response_string_lengths(群信息字符串长度)和 response_validation(信封、业务层、布尔字段、roomInfo 和群 ID 校验结果),不返回这些字段的原始字符串值。full_url_same_host 仅表示与原入口主域名相同;官方地区域名可使其为 false,应结合 full_url_host_allowed/full_url_allowed 判断。字段按到达阶段提供。探针不返回原始链接、ticket、exportkey、Cookie 或鉴权 header 值,也不提供任意 URL、原生方法执行能力。

可运行项目自带只读验证脚本(真实 ID 由调用方在命令行传入,不写入文件):

python tests/group_invitation_smoke.py --base-url http://<手机IP>:19088 --message-id <刚收到的消息ID>

排障按 context → auth → info 检查;确认 status=ready 后按业务需要调用接受接口。脱敏探针 JSON 可定位原消息、ABI、A8Key 或 HTTP 问题,避免盲目重建。若 auth 成功但 info 失败,检查 http_status、双层业务码、网络错误与 header 名称。用户已确认邀请查询与接受入群在微信 8.0.80 验证通过。实现不再按固定版本号拦截,仍检查实际原生类、方法和参数类型。过期/受限邀请、网络异常、账号切换及跨重启幂等按本节状态和重试边界处理。Apifox GUI 导入未测试。

HTTP 调用示例:

POST /accept_group_invitation HTTP/1.1
Content-Type: application/json

{"message_id":"123456789012345678"}

群管理员与群免打扰

下列两项使用相同的群 ID 和业务状态约定;示例 ID 均为虚构。

用途 HTTP 路径(均为 POST)/命令名 必填参数
添加/移除管理员、转让群主 /group_admin_operate/group_admin_operate room_id、oper_type、member_ids
设置当前账号的群免打扰 /set_group_msg_silence/set_group_msg_silence room_id、silence

需要正常鉴权和登录,拒绝未知字段。群管理与免打扰受发送写入状态约束。群 ID 必须是普通微信群真实 ...@chatroom,不接受群名或 OpenIM 群。

群管理员操作

{"room_id":"123456789@chatroom","oper_type":1,"member_ids":["wxid_member_a"]}
oper_type 操作 CGI member_ids
1 添加管理员 889 非空数组,可批量
2 移除管理员 259 非空数组,可批量
3 转让群主 990 去重后恰好一人

oper_type 必须是 JSON 整数,拒绝布尔值、字符串。成员必须是群内其他普通微信成员的真实 user_name/wxid,不接受昵称或本人;数组去重并保留顺序。当前账号必须为群主,无法从本地群资料确认权限或成员时先刷新群资料。同一群同时只处理一个权限变更,全局最多 32 项待处理。

status ok 含义
succeeded true 本次匹配的微信响应明确成功,wechat_ret=0、server_confirmed=true
failed false 前置校验失败,或微信明确拒绝;查看 error_code/error
unknown false 已调用但未取得完整确认、超时或账号变化,操作可能已经生效

accepted 仅为原生方法的 BOOL 返回;request_submitted 仅表示取得本次原生事件 ID,均不能单独判断成功。每次调用等待约 30 秒并一次返回结果,调用方超时建议至少 40 秒,无需业务状态轮询。超时、断线或 unknown 时先核实群状态,不要自动重新提交;转让成功后原群主不再具备群主权限。

返回保留 room_id、oper_type、去重后的 member_ids,以及以下诊断字段:

字段 含义
accepted、request_submitted、server_confirmed 分别表示原生接受、取得事件 ID、服务端明确确认
request_cgi、event_id 本次 CGI 与事件 ID,未取得时为 null;不是业务轮询凭证
wechat_ret、wechat_error_message 微信原始业务错误码及说明,错误码未知为 null
message_type 原生消息状态,未取得为 null
transport_error_type、transport_error_code 原生传输错误类型与错误码,未取得为 null

常见 error_code:OWNER_REQUIRED、ROOM_STATE_UNAVAILABLE、OPERATION_BUSY、WRITE_DISABLED、REQUEST_NOT_CONFIRMED、WECHAT_REQUEST_REJECTED、OPERATION_TIMEOUT、ACCOUNT_CHANGED。不要把 null 错误码按 0 处理。

群聊消息免打扰

{"room_id":"123456789@chatroom","silence":true}

silence:true 开启免打扰,false 恢复通知。必须显式传入 JSON 布尔值,拒绝 0/1、字符串、null 和缺省。普通群成员即可操作,只影响当前账号的消息提醒设置。

status ok 含义
applied_locally true 原生接受修改,联系人数据库回读与目标一致,local_verified=true
unchanged true 数据库中原值已一致,already_set=true、accepted=false、sync_requested=false、local_verified=true
failed false 参数、账号、群状态或写开关等前置检查失败
unknown false 已进入修改路径,但原生返回失败、回读不一致或账号变化,结果未知

响应保留 room_id、目标值 silence、accepted、sync_requested、already_set、local_verified、server_confirmed、status;非法或缺失的 silence 可为 null。accepted 是原生 BOOL,sync_requested 只表示进入原生同步路径;server_confirmed 固定为 false,本地数据库确认不等于服务端同步 ACK。失败或未知时附 error_code/error,未知结果先核实设置,不自动重提。

HTTP 调用与结果

请求使用 Content-Type: application/json,沿用本篇鉴权。上述参数直接放在请求体,业务结果直接位于响应顶层。业务失败或未知也返回 HTTP 200,必须检查 ok/status;通用鉴权、JSON 解析等错误沿用本篇约定,响应附 version。

管理员成功响应格式示例:

{
  "ok": true,
  "room_id": "123456789@chatroom",
  "oper_type": 1,
  "member_ids": [
    "wxid_member_a"
  ],
  "status": "succeeded",
  "accepted": true,
  "request_submitted": true,
  "server_confirmed": true,
  "request_cgi": 889,
  "event_id": 42,
  "wechat_ret": 0,
  "wechat_error_message": "",
  "message_type": 0,
  "transport_error_type": 0,
  "transport_error_code": 0,
  "version": "8.0.80-2"
}

验证范围

用户已确认 HTTP 群免打扰正常,管理员添加、移除和群主转让也均有 ok=true、status=succeeded、wechat_ret=0、server_confirmed=true 的真机回包。用户现已确认相关业务在微信 8.0.80 验证通过。这些群管理接口不包含进群申请审核。

POST /quit_group

用途:退出群聊。

字段 类型 必填 说明
id string ✅ 群 ID

成功响应:{"ok": true, "id": "..."}


11. 会话管理

POST /delete_session

用途:删除指定会话(聊天列表里的那条)。

字段 类型 必填 说明
id string ✅ 会话 ID(群 ID 或好友 wxid)

成功响应:{"ok": true, "id": "1234567890@chatroom"}

注意:删除会话不会删除聊天记录,也不会删除好友关系。


12. 红包与转账

POST /receive_red_packet

用途:领取红包。

字段 类型 必填 说明
red_packet_id string ✅ 红包 ID,从红包事件里拿

响应:透传领取结果(含领取状态、金额等字段)。失败时 400,但响应体里仍然带业务结果,便于你判断是"已经被领完"还是"参数不对"。


POST /red_packet_detail

用途:查询红包详情(不领取)。

字段 类型 必填 说明
red_packet_id string ✅ 红包 ID

响应:透传详情结果。


POST /receive_transfer

用途:确认收款。参数 transfer_id、message_id 均为 string,至少一项非空,推荐两个都传且对应同一笔转账。

响应:返回精简业务结果,成功 HTTP 200,业务失败 HTTP 400;进入收款业务后,失败也保留下表字段。鉴权、插件/发送开关等前置拒绝沿用通用错误格式,不保证收款业务字段齐全。

字段 类型 说明
ok boolean 本次调用是否成功;true 仍需结合 status、confirmed 判断是否确认收款
version string 插件版本,例如 8.0.80-2
transfer_id、message_id string 本笔转账与消息编号,未能解析时可能为空字符串
status string 本次收款状态;见下方说明
accepted boolean 已进入现有收款流程的状态标记;不能代替 confirmed 判断到账
confirmed boolean 是否已确认本笔收款成功
callback_received boolean 是否收到匹配本次操作的确认收款回包;独立查询完成确认时也可能为 false
ret_code integer / null 确认收款回包返回码;没有取得合法返回码时为 null,不以 0 代填
error string 失败原因;成功时为空字符串
native_status integer(可选) 仅在真实资金状态查询完成本次收款操作时出现;不根据 callback_ok 推测为 2001

收到正常确认收款回包的示例:

{
  "ok": true,
  "version": "8.0.80-2",
  "transfer_id": "transfer_example",
  "message_id": "message_example",
  "status": "callback_ok",
  "accepted": true,
  "confirmed": true,
  "callback_received": true,
  "ret_code": 0,
  "error": ""
}

接口等待原生回包约 5 秒。status="confirm_invoked" 表示已发起确认、等待已超时,返回 ok=true, accepted=true, confirmed=false, callback_received=false, ret_code=null,不能认定资金已到账。callback_received 仅是辅助信号;匹配实际确认收款回包且成功时为 callback_ok,或独立查询取得原生状态 2001 后为 confirmed,才会得到 ok=true, confirmed=true。

收到回包却缺少合法返回码时,业务失败 HTTP 400 示例:

{
  "ok": false,
  "version": "8.0.80-2",
  "transfer_id": "transfer_example",
  "message_id": "message_example",
  "status": "callback_unknown",
  "accepted": true,
  "confirmed": false,
  "callback_received": true,
  "ret_code": null,
  "error": "转账回调缺少状态码,收款结果未知,请勿自动重试"
}

callback_unknown 或等待超时不要直接重试;使用下方 get_transfer_status 查询,原生状态 2001 才确认已收取。接收与退还同笔互斥,未知结果先查终态。

业务响应不包含整份 content/content_xml、native_url、callback、pay_info_probe 或 runtime_probe。排错时用 POST /debug/transfer_probe 在请求体传 transfer_id/message_id 查询;无参数 GET /debug/transfer_probe 读取最近快照。完整诊断快照也保留相关上下文,它们不作为收款成功依据。


转账:退还与查询状态

接口:POST /refund_transfer 退还待收取转账;POST /get_transfer_status 只查询服务器资金状态。退还要求插件和发送开关开启;查询不受发送开关限制;HTTP 监听仍可用且已通过鉴权时可查询,业务服务不另外用插件开关拦截这项只读操作。

请求体示例(两个接口通用):

{
  "transfer_id": "transfer_example",
  "message_id": "message_example"
}

HTTP 成功返回 200,业务失败返回 400,响应体直接保留完整业务结果。鉴权等通道错误按本文第 3 节处理。下面依次是退还已提交仍等待、查询待收取、已确认退还和缓存失效示例:

{
  "ok": true,
  "transfer_id": "transfer_example",
  "message_id": "message_example",
  "accepted": true,
  "confirmed": false,
  "status": "refund_pending",
  "native_status": null,
  "ret_code": null,
  "error_code": "",
  "error": ""
}
{
  "ok": true,
  "transfer_id": "transfer_example",
  "message_id": "message_example",
  "accepted": false,
  "confirmed": false,
  "status": "waiting_receive",
  "native_status": 2000,
  "ret_code": 0,
  "error_code": "",
  "error": "",
  "can_refund": true,
  "status_description": "等待收款",
  "native_status_name": "waiting_receive"
}
{
  "ok": true,
  "transfer_id": "transfer_example",
  "message_id": "message_example",
  "accepted": true,
  "confirmed": true,
  "status": "refunded",
  "native_status": 2002,
  "ret_code": 0,
  "error_code": "",
  "error": ""
}
{
  "ok": false,
  "transfer_id": "",
  "message_id": "",
  "accepted": false,
  "confirmed": false,
  "status": "failed",
  "native_status": null,
  "ret_code": null,
  "error_code": "CACHE_NOT_FOUND",
  "error": "转账上下文已失效,请使用本次运行收到的转账消息"
}

本轮状态(2026-11-05):用户此前已确认普通微信群内指定给自己的个人转账可领取;在 0.8.79-79 交付后,用户回传同笔转账查询 waiting_receive / native_status=2000 / can_refund=true,以及退还后 refunded / native_status=2002 / accepted=true / confirmed=true / ret_code=0,群内个人转账的查询和退还正常路径已实测通过。接口参数及结果结构不变,群 ID 从原消息读取,无需调用方补传。标准 Ubuntu 构建通过,新包为 0.8.79-79;旧包 0.8.79-78 的查询/退还仍保留群限制。此次回包未单独覆盖 WebSocket/长轮询外层收发、结果事件、重复操作、断网与账号切换,也未重新回传接收结果。

范围与前置条件:本轮源码支持当前登录账号作为收款人的普通微信个人转账(app_msg_type=2000),包括普通微信群内他人指定给当前账号的个人转账;不包括群收款/AA、企业互通群、任一方为 @openim 的交易、已收取后的退款或部分金额退还。群内转账须能读取原消息的个人付款人、接收人及群 ID,并确认本地群联系人属于普通微信群;群资料缺失或类型无法确认时仍拒绝。查询与退还都依赖本次运行收到的原转账消息,并要求缓存包含付款人、交易编号和已明确读取的非负整数有效期(允许 0,不等同于字段缺失);本版不提供按历史交易号恢复上下文的入口。上下文按当前账号保存在内存中,最多 120 笔;重启、账号会话变化或淘汰后可能返回 CACHE_NOT_FOUND,持久化 ID 不能恢复该缓存。

请求参数:两个接口使用同一组参数,无其他业务输入;不能补传付款人、金额、交易号或有效期绕过原消息核验。

参数 类型 必填与默认值 说明
transfer_id string 与 message_id 至少一项非空;无默认值 原转账事件的转账 ID,按字符串原样保存
message_id string 与 transfer_id 至少一项非空;无默认值 原转账消息 ID,按字符串原样保存

可以省略未提供的字段;不得传数字、null、数组或对象。去除首尾空白后两个字段都为空时失败;同时提供时必须指向同一笔,否则 ID_MISMATCH。

结果字段:下表说明业务结果,外层封装按本节本模式的示例读取。进入业务服务后固定返回这些基础字段;通道鉴权、插件禁用等更早的拒绝可采用本模式通用错误外壳,不能假设总有业务字段。

字段 类型 说明
ok boolean 本次调用是否按该操作的约定完成;查询成功或退还已进入等待都可能为 true,不代表已退还
transfer_id string 解析到的转账 ID;前置失败可能为空串
message_id string 解析到的消息 ID;前置失败可能为空串
accepted boolean 退还动作已进入原生提交阶段;查询恒为 false。true 时即使发生异常,也不能排除已发出交易
confirmed boolean 已取得原生终态 2001/2002/2003;不是退还成功专属标志
status string 规范化业务状态,见下表
native_status integer 或 null 微信原生资金状态;未取得为 null,未知数值保留原值
ret_code integer 或 null 微信回包错误码;未取得为 null;非零时结合 error_code 判断
error_code string 业务错误码;成功时为空字符串,不省略
error string 错误说明;成功时为空字符串

查询结果还可能返回 can_refund(boolean)、status_description(string)和 native_status_name(string,微信回包原生名称,可能为空);微信错误回包可能带 wx_error_type(integer 或 null;回包未提供时为 null)。can_refund=true 仅表示服务器状态待收取、普通交易、双方匹配且无同笔未决收款/退还占用;不包含发送开关,也不保证后续风控允许退还。

status native_status confirmed 含义与处理
waiting_receive 2000 false 等待收款;查询不会主动收款或退还
received 2001 true 已收取;本版不能再退还,退还调用返回 NOT_REFUNDABLE
refunded 2002 true 唯一确认已退还的资金状态;退还预检发现已退还时 ok=true, accepted=false
expired 2003 true 已过期;退还调用返回 NOT_REFUNDABLE
unknown 2004/2005/其他原值 false 含义未核实;查询保留原值,退还预检返回 NOT_REFUNDABLE 且不提交。已提交后的确认查询遇到未知/非终态时保持 refund_pending
refund_pending null false 退还已提交,约 5 秒短等待结束仍无终态;继续查询
refund_unknown 通常 null false 提交后出现异常或无法验证回包;不能直接认定失败或自动重提
failed null 或已取得原值 由原值决定 参数、前置或微信回包错误;必须一起读取 accepted、error_code 和 ret_code

成功判定与等待:只有 status="refunded" 且 native_status=2002 才代表已退还。ok=true、accepted=true、HTTP/命令传输成功或收到事件,均不能单独作为退还成功判据。两个新操作在当前请求/命令中短等待约 5 秒;排队、主线程调度和网络时间另计,客户端建议至少等待 15 秒。预检/查询超时且未提交时返回 QUERY_TIMEOUT, accepted=false;已提交但仍无终态时返回 refund_pending, accepted=true。提交后的确认查询可能返回 WECHAT_ERROR, accepted=true,仍须继续查询,不能认定退还确定失败。

重试与互斥:同一笔转账的接收与退还互斥,未决操作会返回 TRANSFER_BUSY;结果未知时保留占用,查询到终态后可回收占用。退还请求被微信明确拒绝才解除该退款提交的占用。重复调用不是按 request_id 持久幂等:ID 用于定位同笔转账,通道 request_id 只关联命令结果。网络超时、refund_pending、refund_unknown 或 accepted=true 的失败,都应先调用状态查询,不要改 ID、重启或自动重提退还/收款。未决保护不保证跨进程或跨账号会话延续。

业务错误码:失败保留结构化结果,不要只记录错误文字。

error_code 说明
INVALID_ARGUMENT 编号类型错误,或两个编号都为空白;本次未提交退还。
CACHE_NOT_FOUND 本次运行没有该转账上下文,可能已重启或被淘汰;不能补传交易信息绕过。
ID_MISMATCH 两个编号未指向同一笔转账。
NOT_LOGGED_IN 当前微信账号未登录。
NOT_RECEIVER 当前账号不是该转账的接收方。
UNSUPPORTED_TRANSFER 群收款/AA、企业互通等不支持的交易,或无法确认群资料/普通群类型;普通微信群内指定给当前账号的个人转账不因来自群而拒绝。
INCOMPLETE_CONTEXT 原消息缺少付款人、交易编号或可确认的非负整数有效期;明确读取到 0 可以使用,字段缺失仍拒绝。
UNSUPPORTED_RUNTIME 当前微信运行时的请求关联或回包能力未就绪。
TRANSFER_BUSY 同笔转账存在未决收款/退还操作;先查询,不要重提。
CAPACITY_REACHED 未决操作容量已满;先查询已有操作。
ACCOUNT_CHANGED 等待期间账号或账号会话发生变化;旧操作不能在新账号继续。
WRITE_DISABLED 插件或发送开关不允许退还;查询不受发送开关限制。
REQUEST_NOT_CAPTURED 未捕获到可以安全关联的微信请求;根据 accepted 判断是否已进入提交。
NATIVE_EXCEPTION 调用微信发生异常;accepted=true 时结果未知,禁止直接重提。
INVALID_RESPONSE 微信回包格式不完整或无法关联;提交后按未知处理。
WECHAT_ERROR 微信返回错误;读取 ret_code 和可选 wx_error_type。提交后的确认查询报错不等于退还确定失败。
IDENTITY_MISMATCH 服务器交易双方与消息上下文不一致;预检时不会提交,accepted=true 时则表示退还已提交、后续确认结果未知,先查询。
NOT_REFUNDABLE 服务器确认当前状态不能退还;保留真实 status/native_status。
QUERY_TIMEOUT 约 5 秒内未取得查询/预检结果,本次未提交退还。
MAIN_THREAD_CALL 内部调用线程不符合等待要求;应通过本模式的正常入口调用。

验证范围:普通个人转账的正常查询、接收与退还已有用户确认的真机记录:查询取得待收取 2000,退还后确认 2002,接收取得 callback_ok 且 confirmed=true。用户现已确认转账相关功能在微信 8.0.80 验证通过;重复操作、网络异常与账号切换仍按本节状态和重试规则处理。

退款完成/失败/未知时还可能收到 transfer_refund_result 事件;事件不可替代主动查询。


13. 账号资料与个人二维码

POST /clear_gender_region

用途:清除当前账号的性别与地区。

请求字段:无。

成功响应:

{
  "ok": true,
  "fields_cleared": ["sex", "country", "province", "city"],
  "restart_recommended": true
}

restart_recommended: true 表示建议重启微信让改动在界面上生效。


POST /profile_nickname(别名 /profile/nickname)

用途:修改当前账号昵称。

字段 类型 必填 说明
nickname string ✅ 新昵称

成功响应:{"ok": true, "nickname": "...", "restart_recommended": false}

前置条件:发送开关必须开启,否则 400 "profile_nickname is disabled"。


POST /profile/update、/profile/gender、/profile/region、/profile/signature

用途:设置或清空性别、地区、个性签名。上述写接口已通过用户真机 HTTP 全量测试,长轮询与 WebSocket 共用相同实现。

路径 请求示例 说明
/profile/gender {"sex":1} 0 清空、1 男、2 女
/profile/region {"region_code":"CN_Guangdong_Shenzhen"} 按原生地区库设置;空串清空全部地区
/profile/region {"region":{"country":"CN","province":"Guangdong","city":"Shenzhen"}} 自定义地区字符串;空对象清空
/profile/signature {"signature":"今天也要开心"} 空字符串清空签名
/profile/update {"sex":2,"region_code":"CN_Guangdong_Shenzhen","signature":"今天也要开心"} 批量设置以上资料,至少提供一项

参数规则:

  • 未提供的资料字段保持原值;性别、地区、签名单独入口只接受各自字段。未知字段与 null 在提交前拒绝。
  • region_code 与 region 二选一。推荐先用下一节的 /profile/region_codes 查询完整代码。
  • 地区是整组替换:传 region_code:"CN" 会设置国家并清空省市;传 region 时省市缺失也会清空。省不能脱离国家,市不能脱离省。自定义字符串按微信服务器实际处理结果展示。
  • 签名使用微信 CAppUtil.calStringLen: 计数,上限 30。ASCII UTF-16 单元权重 1,其他单元权重 2,总权重除 2 向上取整;例如 30 个中文或 60 个 ASCII 可通过。超限直接拒绝,不截断。
  • 拍一拍独立提交,不能放进 /profile/update。写操作要求发送开关开启。

提交响应示例:

{
  "ok": true,
  "accepted": true,
  "status": "submitted",
  "local_verified": true,
  "server_confirmed": false,
  "requested": {"signature": "今天也要开心"},
  "before": {"sex": 1, "country": "CN", "province": "Guangdong", "city": "Shenzhen", "signature": "", "current_user": "wxid_self"},
  "current": {"sex": 1, "country": "CN", "province": "Guangdong", "city": "Shenzhen", "signature": "今天也要开心", "current_user": "wxid_self"},
  "changed_fields": ["signature"],
  "error": "",
  "readback_error": "",
  "message": "资料已提交微信同步队列;本地读回不代表服务器确认"
}

accepted 表示微信受理,local_verified 表示本地读回,均不代表服务器确认;最终资料以微信展示为准。当前值已一致时返回 status:"unchanged"、accepted:false,不重复提交。失败为 HTTP 400;submitted_with_error 可能已入队,应检查 accepted、current 和错误信息再处理。

批量清空性别、地区和签名:

curl --request POST 'http://172.20.10.5:19088/profile/update' \
  --header 'Content-Type: application/json' \
  --data-raw '{"sex":0,"region_code":"","signature":""}'

POST /profile/region_codes:查询国家、省、市地区代码

用途:只读查询微信原生地区库,取得可直接用于 region_code 的完整代码。不要求发送开关,仍需插件授权。请求体仅接受可选字符串 parent_code;URL 查询参数不参与解析。

请求体 返回
{} 或 {"parent_code":""} 国家/地区列表
{"parent_code":"CN"} 中国省级列表
{"parent_code":"CN_Guangdong"} 广东市级列表

响应示例(仅展示一项):

{
  "ok": true,
  "parent_code": "CN_Guangdong",
  "count": 1,
  "items": [
    {"code": "CN_Guangdong_Shenzhen", "name": "深圳", "parent_code": "CN_Guangdong", "type": 2}
  ],
  "selector_probe": {}
}

count 是本次列表实际数量。items[].code 是完整代码,name 是随微信语言变化的展示名;type 是原生层级标记,取不到为 null。始终用返回的 code 查询下一级或设置地区,不要根据中文名称拼代码。叶节点或不存在的父代码可能返回空列表;空列表不代表查询失败。

以下 curl 可分别导入 Postman / Apifox:

curl --request POST 'http://172.20.10.5:19088/profile/region_codes' \
  --header 'Content-Type: application/json' \
  --data-raw '{}'
curl --request POST 'http://172.20.10.5:19088/profile/region_codes' \
  --header 'Content-Type: application/json' \
  --data-raw '{"parent_code":"CN"}'
curl --request POST 'http://172.20.10.5:19088/profile/region_codes' \
  --header 'Content-Type: application/json' \
  --data-raw '{"parent_code":"CN_Guangdong"}'

POST /profile/pat_suffix:设置或清空拍一拍后缀

请求仅接受 {"pat_suffix":"的小脑袋"};传 {"pat_suffix":""} 清空。发送开关需开启。

微信原生规则先处理空白/换行,再按 charLengthWithEmoOneCharPolicy:YES andIsFullWidth:NO 计数并检查禁止字符。限制来自动态配置,不能简单用字符串长度替代;本次真机上限 10、禁止字符为 <>/,以 /debug/profile_pat_suffix_probe 返回的 capabilities.max_length、capabilities.forbidden_characters 为准。

立即返回的关键字段:

{
  "ok": true,
  "accepted": true,
  "status": "pending",
  "server_confirmed": false,
  "local_verified": false,
  "operation_id": "示例操作UUID",
  "event_id": 123,
  "requested": "的小脑袋",
  "normalized": "的小脑袋",
  "length": 4,
  "max_length": 10,
  "error": ""
}

随后调用 GET /debug/profile_pat_suffix_probe,检查 last_operation:

状态 含义
pending 已受理,等待微信服务器回调
succeeded 且 server_confirmed:true 服务器确认成功
failed 明确失败,查看 error
unknown 120 秒未回调或提交后出现异常,结果未知;不要盲目重试

只保存最近一次操作,重启微信后记录消失;上一项仍 pending 时拒绝第二项提交。用响应的 operation_id / event_id 与 last_operation 对照,避免把别的操作结果当作本次结果。该数字 event_id 是微信 oplog ID,与消息事件的去重键不同。

资料只读探针

方法/路径 参数与用途
GET /debug/profile_probe 当前资料、profile_ready、签名限制和运行时信息
POST /debug/profile_probe {} 查看资料;传资料设置参数可预校验
GET /debug/profile_region_probe 查询国家列表
POST /debug/profile_region_probe 同 /profile/region_codes,可传 parent_code
GET /debug/profile_pat_suffix_probe 当前拍一拍后缀、限制及 last_operation
POST /debug/profile_pat_suffix_probe {} 查状态;传 pat_suffix 可预校验

预校验只返回 validation.valid、normalized、error 和 writes_performed:false,不会提交。探针的 ok:true 仅表示查询完成,还须检查 ready 或 validation.valid。头像探针显示 avatar.write_enabled:false、status:"deferred",本轮未增加头像写接口。

POST /get_self_qrcode:获取自己的二维码

需要正常鉴权和登录,不受发送状态约束。请求体必须为 {};自动使用当前登录账号,不接受 appId、wxid、style、refresh 或其他字段。本次请求二维码 URL,必要时生成 PNG;不读取旧磁盘图片,也不撤销旧二维码。同账号并发查询合并,等待约 30 秒,调用方超时建议至少 40 秒。

字段 类型 含义
status string ok、restricted、failed 或 timeout,结合外层 ok 判断成功
wxid string 当前账号 ID,前置失败时可为空
qr_code_url string 二维码内容 URL,可为空;不是图片下载地址
image_base64 string/null PNG Base64,不含 data URI 前缀;无图为 null
image_mime_type string/null 有图片时为 image/png,否则 null
has_qrcode、has_image boolean 本次是否有二维码 URL/可解码图片;有 URL 无图片也可成功
qrcode_status integer/null 微信原始二维码状态,未知为 null,不硬编码具体限制含义
restricted boolean/null 已知状态是否非零,未知为 null
footer_wording string 微信原始提示,可为空
request_submitted boolean 是否取得本次原生事件 ID
request_cgi、event_id integer/null 本次 CGI(168)与事件 ID,未取得为 null
wechat_ret、wechat_error_message integer/null、string 微信原始业务结果与说明
message_type、transport_error_type、transport_error_code integer/null 原生消息/传输状态,未取得为 null

受限或失败时保留原始状态、提示及可用图片,不把受限结果按成功处理。失败时结合 error_code/error,不能只检查图片是否存在。

业务结果位于响应顶层;业务失败或未知也返回 HTTP 200,须结合 ok、status 和 error_code 判断。授权失败为 HTTP 403。个人二维码尚无本轮成功真机记录。


14. 朋友圈

你调用手机HTTP;不是调用后端的/agent/*。示例192.0.2.10:19088为文档占位地址,必须换成你自己的插件地址;媒体上传域名和Token也必须替换。所有示例数据均为虚构。

最短读取流程:

  1. GET /health 确认端口、授权及功能状态,GET /account_status 确认微信登录。
  2. POST /moments/list {};保存首次返回的operation_id,此时pending只是微信正在查询。
  3. 每1~2秒POST /moments/operation {"operation_id":"原编号"},直至得到终态;也可提前启动/events监听完成事件。
  4. 最终从items[]取动态;点开一条用/moments/detail,继续历史用next_cursor,看媒体用该动态的media[].mid。
curl --request POST 'http://192.0.2.10:19088/moments/list' --header 'Content-Type: application/json' --data-raw '{}'
curl --request POST 'http://192.0.2.10:19088/moments/operation' --header 'Content-Type: application/json' --data-raw '{"operation_id":"11111111-1111-4111-8111-111111111111"}'

返回结果怎么判断

status/情况 意义 接下来怎么做
preparing 准备资源或构造任务 等完成事件或查询原operation_id
pending 微信请求或媒体上传进行中 查询原操作,不能再调用入口来“催进度”
succeeded 本次业务完成 按下表读取对应业务结果
failed 本次失败 看error与诊断;保留operation_id;上传可能需要核对后端
unknown 未取得可信最终确认 尤其write_accepted=true时不重发写入;继续查询原操作或核实实际状态
同步返回且没有operation_id 本地权限读取或空参数状态探针 直接使用当前结果,不再查询不存在的操作
业务 成功判断
页面/详情/联网写操作 status=succeeded,通常server_confirmed=true;unchanged表示联网确认无需写入
friend/recent权限查询 同步ok=true、source=local_settings;server_confirmed=false正常
视频准备探针 status=succeeded且media_ready=true;没有发帖,server_confirmed=false正常
本地媒体准备 status=succeeded且media_ready=true,delivery=local,读取media_url
手机主动上传 status=succeeded且media_ready=true且upload_completed=true,delivery=upload,按resource_id读取后端

accepted只表示微信查询/任务受理。互动和单帖权限先查详情,所以accepted=true可能只是详情查询已发出。write_accepted才表示提交了微信写操作;它不用于表达上传文件。server_confirmed只描述微信结果,不描述上传目标;媒体即使上传成功仍为false。

request_id用于关联;HTTP中可选,最长128个UTF-16单位,长轮询/WS从命令外层写入。它不是跨重启的幂等保证。操作记录最多48项,完成记录在后续请求进入时可能淘汰,通常最多保留10分钟;重启即丢失,不是永久任务数据库。账号切换后不能查询旧账号操作,旧账号事件也不会包成新账号事件。

一般查询/资源准备120秒超时且未提交微信写入时失败;已提交写入却未确认时可能unknown,晚回包仍可用更高revision更新原操作。相同范围处理中或unknown锁未释放时会拒绝新任务。网络断开也不能证明微信写入或后端上传没有发生。

首次HTTP受理示例:

{
  "ok": true,
  "status": "pending",
  "accepted": true,
  "write_accepted": false,
  "server_confirmed": false,
  "operation_id": "11111111-1111-4111-8111-111111111111",
  "request_id": "demo-request-001",
  "error": "",
  "action": "list"
}

完成查询示例:

{
  "ok": true,
  "status": "succeeded",
  "operation_id": "11111111-1111-4111-8111-111111111111",
  "request_id": "demo-request-001",
  "action": "list",
  "accepted": true,
  "write_accepted": false,
  "server_confirmed": true,
  "revision": 1,
  "error": "",
  "items": [],
  "next_cursor": "12345678901234567890",
  "has_more": null,
  "snapshot_complete": true,
  "snapshot_source": "network",
  "missing_ids": [],
  "raw_count": 1,
  "truncated": false
}

也可以接收HTTP事件。先记录自己的offset并拉取;每次读取后按返回的next_offset继续,按event_id去重。需要关联body.operation_id与原任务。事件可能早于查询结果到达,后端应能保存并合并。

curl --request POST 'http://192.0.2.10:19088/events' --header 'Content-Type: application/json' --data-raw '{"offset":0,"limit":50,"timeout_seconds":20}'

/events中的完成事件形态(省略通用时间字段):

{
  "ok": true,
  "events": [
    {
      "update_id": 1775000000123,
      "event_name": "moments_result",
      "event_id": "msg:moments:11111111-1111-4111-8111-111111111111:1",
      "account_id": "wxid_self",
      "body": {
        "ok": true,
        "status": "succeeded",
        "operation_id": "11111111-1111-4111-8111-111111111111",
        "request_id": "demo-request-001",
        "action": "list",
        "accepted": true,
        "write_accepted": false,
        "server_confirmed": true,
        "revision": 1,
        "error": "",
        "items": [],
        "next_cursor": "12345678901234567890",
        "has_more": null,
        "snapshot_complete": true,
        "snapshot_source": "network",
        "missing_ids": [],
        "raw_count": 1,
        "truncated": false
      }
    }
  ],
  "next_offset": 1775000000124
}

朋友圈数据怎么继续使用

取到的字段 含义 下一步
operation_id 本次异步操作UUID 用operation查询,不能传给detail
items[].sns_id/item.sns_id 服务器动态ID detail、点赞、评论、删除、单帖权限
next_cursor 下一页边界 同一时间线/同一用户下一次请求的cursor
media[].mid 本帖媒体标识 media/download的media_id;不是URL或数组下标
comments[].comment_id/comment64_id 本帖评论标识 回复时传reply_comment_id,删除时传comment_id
resource_id 你的后端分配的上传资源标识 查询后端存储或生成后端读取地址
media_url 仅本地模式的手机临时文件地址 拼接手机HTTP基址GET,远程上传模式不依赖它

提交的动态ID、评论ID和cursor必须是非零UInt64十进制字符串,不接受JSON数字或溢出。输出sns_id和游标为字符串;评论ID沿用微信原生类型,可能为数字或字符串,后端需要无损解析大整数再转字符串。不要让64位ID经过JavaScript Number;网页demo已有无损保护。media_id保持mid原值,不要求它是十进制数。所有时间戳字段按字段名区分秒(create_time)与毫秒(*_ms)。

动态对象字段包括sns_id、wxid、create_time、content、type、is_mine、liked、like_count、comment_count、private、visibility_type、media、likes、comments。type和visibility_type保留微信原始值,不要把它们直接当发布接口的type/visibility枚举。普通图片动态type通常1,普通视频通常15。

媒体包含mid、type、subType、totalSize、videoDuration、width、height、preview_urls及原生可用的dataUrl/hdUrl/uhdUrl/lowBandUrl/attachUrl/attachThumbUrl。某字段不存在表示原生未提供。CDN地址不保证电脑直接可用;HTTP200也可能是占位图。列表不自动下载整页资源。

评论包含comment_id、comment64_id、wxid、nickname、content、create_time、is_mine及可用的reply_comment_id/reply_comment64_id/reply_wxid;likes沿用类似摘要结构。每条动态媒体最多32项、赞与评论各200项,media_truncated/interactions_truncated为true表示已截断;接口没有继续分页获取全部评论的入口。

历史和快照的正确判断

direction默认head。显式head不能带cursor;传cursor且省略direction时按tail;tail必须带上一页next_cursor,不能传0,不能自行减1,也不接受自定义page_size。页大小由微信控制。

has_more=false才表示原始历史网络空页已确认到头;has_more=null表示暂不确定,有next_cursor可以继续。items不足40条、筛选后空页都不等于到头。has_more不明确但next_cursor=null时,停止本轮继续翻页,不要编造游标;可以保留结果后稍后重新从最新页核实。

snapshot_complete表示本页是否补齐,不是全量历史完成。snapshot_source=network/network_merged_cache区分网络完整对象与网络/缓存合并。missing_ids列出无法补齐的动态,可查detail。unchanged=true也要检查完整性。单页最多200条,truncated表示原始页超出保护上限。

好友时间线是微信当前账号按权限筛选后的信息流,不保证是所有好友相册并集或无限历史。用户相册的 visible_period 使用明确原生字段或三天/半年提示;提示为空仍为 unknown。空页、缓存计数或 ret_tips 均不足以证明被屏蔽;可用 check_visibility 获取首屏诊断。后端自行保存、去重、比较历史;插件不自动定时刷新。

远程后端:手机主动上传媒体

推荐远程接入使用这一流程:后端先分配resource_id和上传地址 → 下发media/download并附upload → 手机调用微信下载、解密或复用缓存 → 手机主动HTTP上传 → 接收moments_result → 后端按resource_id取自己保存的文件。全程无需后端访问手机HTTP,也不会把文件Base64塞进长轮询/WS。

upload字段:

字段 必填/默认 使用说明
url 必填 手机可达的HTTP(S)上传完整地址;可含签名查询参数,不允许URL账号密码、片段或重定向
resource_id 必填 后端自分配的非空标识,最多128个UTF-16单位;用于关联和核实重复上传
method PUT 可选PUT或POST;请求正文是原始文件二进制,不是JSON、Base64或multipart
headers 空对象 可传Authorization或签名所需头;最多16项、单值4096字符、合计16KiB,不接收控制字符或重复大小写头名

插件自动设置Content-Type=image/jpeg或video/mp4、Content-Length。不能覆盖这两个头、Host、Transfer-Encoding、Connection、Cookie、Proxy-Authorization。使用签名上传时,后端需按对应文件类型签名;resource_id不会自动变成HTTP头,后端自行在上传路径或自己的签名头中关联。

后端接收完整文件并成功存储后才返回2xx;推荐201或204。插件不解析上传响应正文,因此响应正文控制在64KiB内;文件访问URL由你的后端通过resource_id自行生成。返回2xx且上传字节完整后才upload_completed=true;30x不跟随,4xx/5xx失败,不进行插件层自动重传。

准备阶段最多120秒;开始上传后另有180秒总上限(请求等待上限90秒),一次上传模式操作最多约300秒。上传过程按需读文件,不整体加载视频。上传中断、超时或成功状态但缺完整传输确认时upload_outcome_unknown=true:后端可能已经存储,先按resource_id核实,再决定是否重传;接收端应对同一resource_id幂等保存。重传由后端显式发起,插件不提供断点续传。

上传URL与鉴权头只用于当前任务,不进入结果、事件或完成后的操作记录。切号、微信退出或进程重启可能中止任务;这不是跨进程持久后台上传。上传模式成功后没有手机media_url,也没有后端文件的expires_at_ms;保留期限由你的后端决定。微信原生缓存可复用;插件生成的JPEG在上传终态清理,不删除微信视频缓存。

已有零依赖示例位于demo/朋友圈媒体上传接收端/server.py:PUT /uploads/{小写UUID}接收文件,要求Authorization: Bearer <MOMENTS_UPLOAD_TOKEN>;GET /files/{同UUID}读取临时文件,支持Range。后端用UUID同时作为resource_id和路径即可。示例保留10分钟、最多16个资源、重启清空;GET链接含不可猜测UUID,知道链接即可读取,生产环境应按自己的账号鉴权和保留策略实现。

网页demo/朋友圈网页工作台可展开“手机主动上传媒体”,填写已部署接收端地址和Token;随后每次点击媒体下载会生成独立UUID并上传,网页从接收端读取。手机不能访问电脑的127.0.0.1,需要使用手机可达的接收端地址。网页仍用HTTP测试业务;长轮询/WS业务后端直接使用本节命令参数即可。

发布、权限与排错边界

发布visibility=public(公开)、private(仅自己)、include(仅指定用户)、exclude(不给指定用户看)。include/exclude须带非空wxids,最多200项;public/private不能带非空名单。新发布和修改已有本人动态均支持这四种范围;不临时修改微信UI全局发帖设置。

资源/场景 当前保护限制
发布正文 微信动态text_limit及原生加权计数校验;接口输入另限32768个UTF-16单位,不等于固定可发32768字
发布图片 1~9张;单张输入20MiB,处理后JPEG合计20MiB,最长边2048
发布视频 输入100MiB;时长读当前微信配置video_duration_limit_seconds;检查有效视频轨道、时长、可播放性;thumb省略自动取封面
下载已发布媒体 单文件120MiB,最多2个并发准备;图片转最长边2048 JPEG,不保证原图字节;视频保留MP4,不转码
视频准备探针 每账号最多1项,不占发布锁;视频100MiB,显式封面20MiB,不创建发布任务
评论 非空,接口最多4096个UTF-16单位;微信服务器仍可能拒绝

这些MiB是插件保护上限,不是微信通用服务器限额。视频时长、正文配置以当前账号探针为准,不能固定写成30秒或2000字。媒体下载成功也不保证所有电脑浏览器支持该视频编码。

好友权限friend查询为本地hide_from/dont_see;recent查询为本人period。修改recent支持three_days/one_month/half_year/all;查看别人的可见期限使用user。post查询是联网详情,返回item、visible_users、excluded_users;visibility_type是原生字段,修改参数仍使用字符串visibility。只允许修改本人动态。

权限写入的server_confirmed=true而local_verified=false表示服务器已成功、本地读回异常,local_update_error给出原因,不应因此再写一次。dont_see完整服务器确认缺失会保留unknown。不要用“本地开关已变化”代替服务器确认。

视频发布前下载支持无文件后缀URL,结合文件头/响应文件名处理,并异步等待AVFoundation元数据。video_diagnostics.stage为download/metadata/thumbnail/ready;保留file_bytes、extension、duration_seconds、video_track_count、playable、thumb_ready等已取得信息。下载及可选thumb_download含http_status、received_bytes、expected_bytes(-1未知)、elapsed_ms、phase及底层error_domain/error_code;系统提供时还有DNS/连接/响应/传输metrics。准备失败不发布。下载/元数据/封面问题可先使用probe检查,不能把probe成功当发布成功。

评论错误保留raw_ret、server_error及comment_diagnostics;引用不存在、本人评论或无权限对象会明确拒绝。点赞、评论、删除和修改已有单帖都先联网详情;一个帖子的处理中任务可能阻止同帖新请求,按原operation_id等结果。

验证范围:读取、发布互动、单帖权限及本地媒体预览已有 HTTP 真机验收记录。用户现已确认朋友圈相关功能(含主动上传)在微信 8.0.80 验证通过。朋友圈实现标识为 moments_20261016_upload_v1,与插件构建标记分开读取。

接口完整用法

下列每项包含请求字段、可直接使用的场景示例、结果含义与下一步。重复字段含义以本章前面的表格为准;所有示例响应均为虚构,省略部分可选字段。

好友最新时间线与历史:/moments/list

每次请求一页当前账号能看到的好友时间线。默认最新页;提供cursor且省略direction时按历史页处理。

参数 类型 要求 含义
direction string 可选 head 最新页;tail 历史页。省略时,有 cursor 按 tail,否则按 head;显式 head 不能带 cursor。
cursor string direction=tail 时必填 上一页返回的 next_cursor,原样传入,不自行减 1。非零 UInt64 十进制字符串,最大 18446744073709551615;不能提交 JSON 数字。
request_id string 可选 可选原任务关联标识,最多128个UTF-16单位;命令通道取外层request_id。不是持久幂等键。

最新页

curl --request POST 'http://192.0.2.10:19088/moments/list' --header 'Content-Type: application/json' --data-raw '{}'

历史下一页

curl --request POST 'http://192.0.2.10:19088/moments/list' --header 'Content-Type: application/json' --data-raw '{"direction":"tail","cursor":"12345678901234567890"}'

结果字段示例(等待终态后):

{
  "ok": true,
  "status": "succeeded",
  "operation_id": "11111111-1111-4111-8111-111111111111",
  "request_id": "demo-request-001",
  "action": "list",
  "accepted": true,
  "write_accepted": false,
  "server_confirmed": true,
  "revision": 1,
  "error": "",
  "items": [
    {
      "sns_id": "12345678901234567890",
      "wxid": "wxid_friend",
      "create_time": 1775000000,
      "content": "示例动态",
      "type": 1,
      "is_mine": false,
      "liked": false,
      "like_count": 0,
      "comment_count": 1,
      "private": false,
      "visibility_type": 1,
      "media": [
        {
          "mid": "example-media-id",
          "type": 2,
          "width": 1080,
          "height": 1440,
          "preview_urls": []
        }
      ],
      "likes": [],
      "comments": [
        {
          "comment_id": 67,
          "comment64_id": "670000000000000001",
          "wxid": "wxid_friend",
          "content": "示例评论",
          "is_mine": false
        }
      ],
      "media_truncated": false,
      "interactions_truncated": false
    }
  ],
  "next_cursor": "12345678901234567890",
  "has_more": null,
  "snapshot_complete": true,
  "snapshot_source": "network",
  "missing_ids": [],
  "raw_count": 1,
  "truncated": false
}

下一步: 取items[].sns_id可查详情或互动;取next_cursor请求下一页;取media[].mid准备媒体。

指定用户相册与可见期限:/moments/user

传 wxid 获取本人或好友相册。visible_period 优先读取原生期限字段;字段不足时仅从明确的三天/半年提示补充,空提示仍为 unknown。visibility_status 是本次响应的可见性判断,不能据此确认被屏蔽、拉黑或删除。

参数 类型 要求 含义
wxid string 必填 用户 wxid,不能是 @chatroom 群 ID。
direction string 可选 head 最新页;tail 历史页。省略时,有 cursor 按 tail,否则按 head;显式 head 不能带 cursor。
cursor string direction=tail 时必填 上一页返回的 next_cursor,原样传入,不自行减 1。非零 UInt64 十进制字符串,最大 18446744073709551615;不能提交 JSON 数字。
check_visibility boolean 可选 默认 false;仅指定用户相册的 head 请求可传。true 时清空本次请求的首屏 MD5,尝试获取完整首屏用于诊断,不保证服务器一定返回完整数据;不支持 timeline 或 tail。
request_id string 可选 可选原任务关联标识,最多128个UTF-16单位;命令通道取外层request_id。不是持久幂等键。

可见性检查(HTTP 请求体或命令 args)

{"wxid":"wxid_xxx","check_visibility":true}

普通请求继续使用微信的 MD5 增量策略。诊断仍复用同一个相册入口;刷新接口在 scope=user、direction=head 时也支持 check_visibility。按原 operation_id 等待终态,items=[] 本身不能证明空相册或被屏蔽。

用户最新页

curl --request POST 'http://192.0.2.10:19088/moments/user' --header 'Content-Type: application/json' --data-raw '{"wxid":"wxid_xxx"}'

用户历史页

curl --request POST 'http://192.0.2.10:19088/moments/user' --header 'Content-Type: application/json' --data-raw '{"wxid":"wxid_xxx","cursor":"12345678901234567890"}'

结果字段示例(等待终态后):

{
  "ok": true,
  "status": "succeeded",
  "operation_id": "11111111-1111-4111-8111-111111111111",
  "request_id": "demo-request-001",
  "action": "user",
  "accepted": true,
  "write_accepted": false,
  "server_confirmed": true,
  "revision": 1,
  "error": "",
  "items": [
    {
      "sns_id": "12345678901234567890",
      "wxid": "wxid_friend",
      "create_time": 1775000000,
      "content": "示例动态",
      "type": 1,
      "is_mine": false,
      "liked": false,
      "like_count": 0,
      "comment_count": 1,
      "private": false,
      "visibility_type": 1,
      "media": [
        {
          "mid": "example-media-id",
          "type": 2,
          "width": 1080,
          "height": 1440,
          "preview_urls": []
        }
      ],
      "likes": [],
      "comments": [
        {
          "comment_id": 67,
          "comment64_id": "670000000000000001",
          "wxid": "wxid_friend",
          "content": "示例评论",
          "is_mine": false
        }
      ],
      "media_truncated": false,
      "interactions_truncated": false
    }
  ],
  "next_cursor": "12345678901234567890",
  "has_more": null,
  "snapshot_complete": true,
  "snapshot_source": "network",
  "missing_ids": [],
  "raw_count": 1,
  "truncated": false,
  "visible_period": "all",
  "visible_period_source": "sns_user_info",
  "visibility_status": "visible",
  "check_visibility": false,
  "request_md5_empty": true,
  "top_raw_count": 0,
  "same_md5_count": 0,
  "raw_ret": 0,
  "privacy_flags_raw": 4096,
  "privacy_recent_raw": 4294967295,
  "ret_tips": "",
  "limited_id": "0",
  "continue_id": "0"
}

可见性诊断字段

字段 类型 含义
visibility_status string visible:本次响应含有效 ID 且非 noChange 的普通或置顶对象;empty_or_restricted:新首屏确认无内容,但无法区分从未发布、无权查看或非好友;unknown:证据不足。
visible_period_source string sns_user_info 原生期限字段;ret_tips 明确提示补充;unknown 未确定。
check_visibility boolean 本次是否请求清空首屏 MD5。
request_md5_empty boolean / null 实际请求 MD5 是否为空;不可读取时为 null,不能仅凭 check_visibility 判断请求内容。
raw_count integer / null 普通 objectList 的原始条数;不可读取时为 null,可能与 items 长度不同。
top_raw_count integer / null 置顶 topListObjectList 的原始条数;置顶对象目前仅用于诊断,不新增到 items。
same_md5_count integer / null objectCountForSameMd5 原始计数;大于零仅说明同 MD5 计数,不能单独证明当前可见。
privacy_recent_raw / privacy_flags_raw integer / null 原生期限小时数和标志位;不可读取时为 null。
continue_id / limited_id string / null 原生 UInt64 继续/限制边界;不可读取时为 null,翻页仍用 next_cursor。

只有原生返回码为 0 或 207、head 请求实际 MD5 为空、普通和置顶条数及同 MD5 计数均明确为零、continue_id 明确为 "0" 时,才报告 empty_or_restricted。同 MD5 未变化、仅有缓存计数、字段缺失或首屏未完成时不能据空数组下结论。

操作状态保持兼容:非零 raw_ret 仍返回 status=failed、ok=false、server_confirmed=false,同时保留取得的诊断字段;visibility_status 独立描述响应证据。没有原生响应的网络失败中,visibility_status 保持 unknown,不输出确定的 blocked 标志。受理结果及失败回调可能只有未知值,必须等待原 operation_id 的终态或对应 moments_result。

下一步: 继续历史时保留同一个wxid并使用本页next_cursor;历史页visible_period=unknown不能覆盖此前已确认的期限。

联网获取动态详情:/moments/detail

根据列表、发布结果或已知sns_id联网查询,返回item。媒体、评论及权限信息仍受当前账号服务器可见范围限制。

参数 类型 要求 含义
sns_id string 必填 目标动态的 sns_id,取自列表、详情或发布结果。非零 UInt64 十进制字符串,最大 18446744073709551615;不能提交 JSON 数字。
request_id string 可选 可选原任务关联标识,最多128个UTF-16单位;命令通道取外层request_id。不是持久幂等键。

动态详情

curl --request POST 'http://192.0.2.10:19088/moments/detail' --header 'Content-Type: application/json' --data-raw '{"sns_id":"12345678901234567890"}'

结果字段示例(等待终态后):

{
  "ok": true,
  "status": "succeeded",
  "operation_id": "11111111-1111-4111-8111-111111111111",
  "request_id": "demo-request-001",
  "action": "detail",
  "accepted": true,
  "write_accepted": false,
  "server_confirmed": true,
  "revision": 1,
  "error": "",
  "item": {
    "sns_id": "12345678901234567890",
    "wxid": "wxid_friend",
    "create_time": 1775000000,
    "content": "示例动态",
    "type": 1,
    "is_mine": false,
    "liked": false,
    "like_count": 0,
    "comment_count": 1,
    "private": false,
    "visibility_type": 1,
    "media": [
      {
        "mid": "example-media-id",
        "type": 2,
        "width": 1080,
        "height": 1440,
        "preview_urls": []
      }
    ],
    "likes": [],
    "comments": [
      {
        "comment_id": 67,
        "comment64_id": "670000000000000001",
        "wxid": "wxid_friend",
        "content": "示例评论",
        "is_mine": false
      }
    ],
    "media_truncated": false,
    "interactions_truncated": false
  }
}

下一步: 点赞、评论使用item.sns_id;回复取本帖comments中的comment_id或comment64_id;媒体下载取本帖media中的mid。

服务端触发刷新并接收结果:/moments/refresh

scope省略时为timeline;scope=user时必须传wxid。刷新获取本次页面快照并产生moments_result,不启动定时任务,也不自动计算全局增删差异。支持与list/user相同的历史参数。

参数 类型 要求 含义
scope string 可选 timeline 当前账号好友时间线,user 指定用户相册。;枚举:timeline, user;默认:timeline
wxid string scope=user 时必填 目标用户的 wxid,不能是群 ID;scope=timeline 无需传入。
direction string 可选 head 最新页;tail 历史页。省略时,有 cursor 按 tail,否则按 head;显式 head 不能带 cursor。
cursor string direction=tail 时必填 上一页返回的 next_cursor,原样传入,不自行减 1。非零 UInt64 十进制字符串,最大 18446744073709551615;不能提交 JSON 数字。
check_visibility boolean 可选 默认 false;仅指定用户相册的 head 请求可传。true 时清空本次请求的首屏 MD5,尝试获取完整首屏用于诊断,不保证服务器一定返回完整数据;不支持 timeline 或 tail。
request_id string 可选 可选原任务关联标识,最多128个UTF-16单位;命令通道取外层request_id。不是持久幂等键。

刷新好友最新页

curl --request POST 'http://192.0.2.10:19088/moments/refresh' --header 'Content-Type: application/json' --data-raw '{"scope":"timeline"}'

刷新用户最新页

curl --request POST 'http://192.0.2.10:19088/moments/refresh' --header 'Content-Type: application/json' --data-raw '{"scope":"user","wxid":"wxid_xxx"}'

结果字段示例(等待终态后):

{
  "ok": true,
  "status": "succeeded",
  "operation_id": "11111111-1111-4111-8111-111111111111",
  "request_id": "demo-request-001",
  "action": "refresh",
  "accepted": true,
  "write_accepted": false,
  "server_confirmed": true,
  "revision": 1,
  "error": "",
  "scope": "timeline",
  "direction": "head",
  "items": [
    {
      "sns_id": "12345678901234567890",
      "wxid": "wxid_friend",
      "create_time": 1775000000,
      "content": "示例动态",
      "type": 1,
      "is_mine": false,
      "liked": false,
      "like_count": 0,
      "comment_count": 1,
      "private": false,
      "visibility_type": 1,
      "media": [
        {
          "mid": "example-media-id",
          "type": 2,
          "width": 1080,
          "height": 1440,
          "preview_urls": []
        }
      ],
      "likes": [],
      "comments": [
        {
          "comment_id": 67,
          "comment64_id": "670000000000000001",
          "wxid": "wxid_friend",
          "content": "示例评论",
          "is_mine": false
        }
      ],
      "media_truncated": false,
      "interactions_truncated": false
    }
  ],
  "next_cursor": "12345678901234567890",
  "has_more": null,
  "snapshot_complete": true,
  "snapshot_source": "network",
  "missing_ids": [],
  "raw_count": 1,
  "truncated": false
}

下一步: 按operation_id关联本次页面;后端自行按sns_id去重、保存历史和比较变化。持续监听事件不会主动刷新。

点赞:/moments/like

先联网查详情,再提交点赞并等待原生确认。已经点赞返回unchanged=true。需开启发送/写入功能。

参数 类型 要求 含义
sns_id string 必填 目标动态的 sns_id,取自列表、详情或发布结果。非零 UInt64 十进制字符串,最大 18446744073709551615;不能提交 JSON 数字。
request_id string 可选 可选原任务关联标识,最多128个UTF-16单位;命令通道取外层request_id。不是持久幂等键。

点赞

curl --request POST 'http://192.0.2.10:19088/moments/like' --header 'Content-Type: application/json' --data-raw '{"sns_id":"12345678901234567890"}'

结果字段示例(等待终态后):

{
  "ok": true,
  "status": "succeeded",
  "operation_id": "11111111-1111-4111-8111-111111111111",
  "request_id": "demo-request-001",
  "action": "like",
  "accepted": true,
  "write_accepted": true,
  "server_confirmed": true,
  "revision": 1,
  "error": "",
  "sns_id": "12345678901234567890"
}

下一步: 最终成功后可重新查详情显示最新赞和评论;不要因第一次pending再提交一次点赞。

取消本人点赞:/moments/unlike

只取消当前账号的点赞;原本未点赞返回unchanged=true。需开启发送/写入功能。

参数 类型 要求 含义
sns_id string 必填 目标动态的 sns_id,取自列表、详情或发布结果。非零 UInt64 十进制字符串,最大 18446744073709551615;不能提交 JSON 数字。
request_id string 可选 可选原任务关联标识,最多128个UTF-16单位;命令通道取外层request_id。不是持久幂等键。

取消点赞

curl --request POST 'http://192.0.2.10:19088/moments/unlike' --header 'Content-Type: application/json' --data-raw '{"sns_id":"12345678901234567890"}'

结果字段示例(等待终态后):

{
  "ok": true,
  "status": "succeeded",
  "operation_id": "11111111-1111-4111-8111-111111111111",
  "request_id": "demo-request-001",
  "action": "unlike",
  "accepted": true,
  "write_accepted": false,
  "server_confirmed": true,
  "revision": 1,
  "error": "",
  "sns_id": "12345678901234567890",
  "unchanged": true
}

下一步: 最终成功后可查详情更新显示。unchanged=true表示无需再次写入。

评论与回复他人评论:/moments/comment

普通评论只传sns_id/content;回复增加本帖可见评论的reply_comment_id,可匹配comment_id或comment64_id。当前微信原生实测不能回复本人评论,提交前明确拒绝,不降级为普通评论。content非空,接口最多4096个UTF-16单位,这不是已验证的微信服务器字数上限。

参数 类型 要求 含义
sns_id string 必填 目标动态的 sns_id,取自列表、详情或发布结果。非零 UInt64 十进制字符串,最大 18446744073709551615;不能提交 JSON 数字。
content string 必填 非空评论,插件输入上限4096个UTF-16单位;不是已验证微信服务器字数上限。
reply_comment_id string 回复他人评论时必填 本帖可见评论的 comment_id 或 comment64_id,无损转成字符串;普通评论省略。非零 UInt64 十进制字符串,最大 18446744073709551615;不能提交 JSON 数字。
request_id string 可选 可选原任务关联标识,最多128个UTF-16单位;命令通道取外层request_id。不是持久幂等键。

评论

curl --request POST 'http://192.0.2.10:19088/moments/comment' --header 'Content-Type: application/json' --data-raw '{"sns_id":"12345678901234567890","content":"测试评论"}'

回复评论

curl --request POST 'http://192.0.2.10:19088/moments/comment' --header 'Content-Type: application/json' --data-raw '{"sns_id":"12345678901234567890","content":"测试回复","reply_comment_id":"12345"}'

结果字段示例(等待终态后):

{
  "ok": true,
  "status": "succeeded",
  "operation_id": "11111111-1111-4111-8111-111111111111",
  "request_id": "demo-request-001",
  "action": "comment",
  "accepted": true,
  "write_accepted": true,
  "server_confirmed": true,
  "revision": 1,
  "error": "",
  "sns_id": "12345678901234567890",
  "comment_id": "",
  "raw_ret": 0
}

下一步: 最终成功后重新查detail取得评论列表和可用于后续删除/回复的评论ID;即使成功结果comment_id为空,也不要重发。

删除评论:/moments/delete_comment

允许删除本人评论,或本人动态下的可见评论;不能删除他人动态中他人的评论。comment_id可使用本帖comment_id或comment64_id。需开启发送/写入功能。

参数 类型 要求 含义
sns_id string 必填 目标动态的 sns_id,取自列表、详情或发布结果。非零 UInt64 十进制字符串,最大 18446744073709551615;不能提交 JSON 数字。
comment_id string 必填 本帖待删除评论的 comment_id 或 comment64_id,无损转成字符串。非零 UInt64 十进制字符串,最大 18446744073709551615;不能提交 JSON 数字。
request_id string 可选 可选原任务关联标识,最多128个UTF-16单位;命令通道取外层request_id。不是持久幂等键。

删除本人评论

curl --request POST 'http://192.0.2.10:19088/moments/delete_comment' --header 'Content-Type: application/json' --data-raw '{"sns_id":"12345678901234567890","comment_id":"12345"}'

结果字段示例(等待终态后):

{
  "ok": true,
  "status": "succeeded",
  "operation_id": "11111111-1111-4111-8111-111111111111",
  "request_id": "demo-request-001",
  "action": "delete_comment",
  "accepted": true,
  "write_accepted": true,
  "server_confirmed": true,
  "revision": 1,
  "error": "",
  "sns_id": "12345678901234567890"
}

下一步: 最终成功后查detail核对列表。若原评论已不在可见列表,会明确失败,不推断为已经删除成功。

发布文字、图文或视频:/moments/publish

type=text/images/video,默认text;visibility默认public。媒体来源为手机可访问的HTTP(S)地址或手机绝对路径,不能传电脑C盘路径。下载、解码、封面完成后才提交微信发布。需开启发送/写入功能。

参数 类型 要求 含义
type string 可选,默认 text text 纯文字、images 图文、video 视频。
content string type=text 时必填且非空 图文/视频可省略。按微信当前动态配置和原生加权计数校验,接口最多 32768 个 UTF-16 单位。
visibility string 可选 public 公开、private 仅自己、include 指定人可见、exclude 不给指定人看。;枚举:public, private, include, exclude;默认:public
wxids array include/exclude时必填 include/exclude 必须非空,其他可见范围须为空或省略;重复 wxid 去重。
images array type=images 时必填 1~9 个手机本地绝对路径或 HTTP(S) 图片 URL。
video string type=video 时必填 手机视频绝对路径或 HTTP(S) URL。
thumb string 可选 可选封面手机绝对路径或HTTP(S) URL;省略则从视频生成。
request_id string 可选 可选原任务关联标识,最多128个UTF-16单位;命令通道取外层request_id。不是持久幂等键。

文字(仅自己)

curl --request POST 'http://192.0.2.10:19088/moments/publish' --header 'Content-Type: application/json' --data-raw '{"type":"text","content":"朋友圈测试","visibility":"private"}'

图文(仅自己)

curl --request POST 'http://192.0.2.10:19088/moments/publish' --header 'Content-Type: application/json' --data-raw '{"type":"images","content":"图文测试","images":["https://example.com/image.jpg"],"visibility":"private"}'

视频(仅自己)

curl --request POST 'http://192.0.2.10:19088/moments/publish' --header 'Content-Type: application/json' --data-raw '{"type":"video","content":"视频测试","video":"https://example.com/video.mp4","visibility":"private"}'

指定人可见

curl --request POST 'http://192.0.2.10:19088/moments/publish' --header 'Content-Type: application/json' --data-raw '{"type":"text","content":"指定可见测试","visibility":"include","wxids":["wxid_xxx"]}'

不给指定人看

curl --request POST 'http://192.0.2.10:19088/moments/publish' --header 'Content-Type: application/json' --data-raw '{"type":"text","content":"示例","visibility":"exclude","wxids":["wxid_friend"]}'

结果字段示例(等待终态后):

{
  "ok": true,
  "status": "succeeded",
  "operation_id": "11111111-1111-4111-8111-111111111111",
  "request_id": "demo-request-001",
  "action": "publish",
  "accepted": true,
  "write_accepted": true,
  "server_confirmed": true,
  "revision": 1,
  "error": "",
  "sns_id": "12345678901234567890",
  "local_sns_id": "local-example"
}

下一步: 等待最终服务器确认后使用sns_id查详情、修改权限或删除。local_sns_id只是本地编号,不能代替服务器sns_id。

删除本人动态:/moments/delete

联网确认作者为当前账号后删除,仅支持本人已发布动态。需开启发送/写入功能。

参数 类型 要求 含义
sns_id string 必填 目标动态的 sns_id,取自列表、详情或发布结果。非零 UInt64 十进制字符串,最大 18446744073709551615;不能提交 JSON 数字。
request_id string 可选 可选原任务关联标识,最多128个UTF-16单位;命令通道取外层request_id。不是持久幂等键。

删除本人动态

curl --request POST 'http://192.0.2.10:19088/moments/delete' --header 'Content-Type: application/json' --data-raw '{"sns_id":"12345678901234567890"}'

结果字段示例(等待终态后):

{
  "ok": true,
  "status": "succeeded",
  "operation_id": "11111111-1111-4111-8111-111111111111",
  "request_id": "demo-request-001",
  "action": "delete",
  "accepted": true,
  "write_accepted": true,
  "server_confirmed": true,
  "revision": 1,
  "error": "",
  "sns_id": "12345678901234567890"
}

下一步: 等待服务器确认;结果未知时保留原操作核实,不能只因界面消失就重新删除。

查询好友、期限、单帖权限:/moments/permissions/query

type=friend/recent同步读取本地设置,不产生operation_id和完成事件;server_confirmed=false正常。friend中dont_see=null表示原生分组尚未加载,不能当false。type=post会联网查询并返回操作编号。

参数 类型 要求 含义
type string 必填,无默认值 friend 好友权限、recent 本人可见期限、post 单条动态可见范围。
wxid string type=friend 时必填 目标用户的 wxid,不能是群 ID;type=recent/post 无需传入。
sns_id string type=post 时必填 目标动态的 sns_id;type=friend/recent 无需传入。非零 UInt64 十进制字符串,最大 18446744073709551615;不能提交 JSON 数字。
request_id string 可选 可选原任务关联标识,最多128个UTF-16单位;命令通道取外层request_id。不是持久幂等键。

好友权限

curl --request POST 'http://192.0.2.10:19088/moments/permissions/query' --header 'Content-Type: application/json' --data-raw '{"type":"friend","wxid":"wxid_xxx"}'

本人可见期限

curl --request POST 'http://192.0.2.10:19088/moments/permissions/query' --header 'Content-Type: application/json' --data-raw '{"type":"recent"}'

单帖可见范围

curl --request POST 'http://192.0.2.10:19088/moments/permissions/query' --header 'Content-Type: application/json' --data-raw '{"type":"post","sns_id":"12345678901234567890"}'

结果字段示例(同步返回):

{
  "ok": true,
  "type": "friend",
  "wxid": "wxid_friend",
  "source": "local_settings",
  "server_confirmed": false,
  "hide_from": false,
  "dont_see": null
}

recent同步返回{ok:true,type:"recent",source:"local_settings",server_confirmed:false,hours:72,period:"three_days"};post须等待终态,返回item及visible_users/excluded_users。以上三种场景不能统一假设都有operation_id。

下一步: 修改好友权限用type=friend;改本人对外期限用type=recent;改已发布本人动态用type=post。查看对方期限则使用moments_user。

修改好友、期限、单帖权限:/moments/permissions/update

friend的hide_from(不让他看我)与dont_see(我不看他)为独立开关;enabled必须是真正JSON布尔值,false解除。recent修改本人可见期限;post只修改本人动态的范围。需开启发送/写入功能。

参数 类型 要求 含义
type string 必填,无默认值 friend 好友权限、recent 本人可见期限、post 单条动态可见范围。
wxid string type=friend 时必填 目标用户的 wxid,不能是群 ID;type=recent/post 无需传入。
direction string type=friend 时必填,无默认值 hide_from 不让他看我;dont_see 我不看他。
enabled boolean 修改好友权限时必填 严格 JSON 布尔值;true 开启,false 解除。
period string 修改本人期限时必填 修改本人期限时必填;枚举:three_days, one_month, half_year, all
sns_id string type=post 时必填 本人动态的 sns_id;type=friend/recent 无需传入。非零 UInt64 十进制字符串,最大 18446744073709551615;不能提交 JSON 数字。
visibility string 可选 public 公开、private 仅自己、include 指定人可见、exclude 不给指定人看。;枚举:public, private, include, exclude;默认:public
wxids array include/exclude时必填 include/exclude 必须非空,其他可见范围须为空或省略;重复 wxid 去重。
request_id string 可选 可选原任务关联标识,最多128个UTF-16单位;命令通道取外层request_id。不是持久幂等键。

不让他看我

curl --request POST 'http://192.0.2.10:19088/moments/permissions/update' --header 'Content-Type: application/json' --data-raw '{"type":"friend","wxid":"wxid_xxx","direction":"hide_from","enabled":true}'

我不看他

curl --request POST 'http://192.0.2.10:19088/moments/permissions/update' --header 'Content-Type: application/json' --data-raw '{"type":"friend","wxid":"wxid_xxx","direction":"dont_see","enabled":true}'

解除我不看他

curl --request POST 'http://192.0.2.10:19088/moments/permissions/update' --header 'Content-Type: application/json' --data-raw '{"type":"friend","wxid":"wxid_xxx","direction":"dont_see","enabled":false}'

本人仅三天可见

curl --request POST 'http://192.0.2.10:19088/moments/permissions/update' --header 'Content-Type: application/json' --data-raw '{"type":"recent","period":"three_days"}'

本人全部可见

curl --request POST 'http://192.0.2.10:19088/moments/permissions/update' --header 'Content-Type: application/json' --data-raw '{"type":"recent","period":"all"}'

本人单帖仅自己

curl --request POST 'http://192.0.2.10:19088/moments/permissions/update' --header 'Content-Type: application/json' --data-raw '{"type":"post","sns_id":"12345678901234567890","visibility":"private"}'

本人单帖不给指定人看

curl --request POST 'http://192.0.2.10:19088/moments/permissions/update' --header 'Content-Type: application/json' --data-raw '{"type":"post","sns_id":"12345678901234567890","visibility":"exclude","wxids":["wxid_xxx"]}'

结果字段示例(等待终态后):

{
  "ok": true,
  "status": "succeeded",
  "operation_id": "11111111-1111-4111-8111-111111111111",
  "request_id": "demo-request-001",
  "action": "permissions/update",
  "accepted": true,
  "write_accepted": true,
  "server_confirmed": true,
  "revision": 1,
  "error": "",
  "type": "friend",
  "direction": "dont_see",
  "enabled": false,
  "local_verified": true
}

下一步: 等待服务器确认后再查询对应权限。服务器已确认但local_verified=false时先核对本地同步,不要重复修改服务器。dont_see缺完整确认时可能unknown,查询原操作。

查询原异步操作:/moments/operation

传原operation_id读取当前账号内存操作记录,不创建新业务任务。返回的action/request_id仍属于原任务。查到记录一律HTTP200,包括failed/unknown;不存在、跨账号或已淘汰为HTTP400。

参数 类型 要求 含义
operation_id string 必填 上一步返回的操作UUID,查询时始终保持同一值。
request_id string 可选 可选原任务关联标识,最多128个UTF-16单位;命令通道取外层request_id。不是持久幂等键。

操作结果

curl --request POST 'http://192.0.2.10:19088/moments/operation' --header 'Content-Type: application/json' --data-raw '{"operation_id":"替换为实际operation_id"}'

结果字段示例(等待终态后):

{
  "ok": true,
  "status": "succeeded",
  "operation_id": "11111111-1111-4111-8111-111111111111",
  "request_id": "demo-request-001",
  "action": "list",
  "accepted": true,
  "write_accepted": false,
  "server_confirmed": true,
  "revision": 1,
  "error": "",
  "items": [
    {
      "sns_id": "12345678901234567890",
      "wxid": "wxid_friend",
      "create_time": 1775000000,
      "content": "示例动态",
      "type": 1,
      "is_mine": false,
      "liked": false,
      "like_count": 0,
      "comment_count": 1,
      "private": false,
      "visibility_type": 1,
      "media": [
        {
          "mid": "example-media-id",
          "type": 2,
          "width": 1080,
          "height": 1440,
          "preview_urls": []
        }
      ],
      "likes": [],
      "comments": [
        {
          "comment_id": 67,
          "comment64_id": "670000000000000001",
          "wxid": "wxid_friend",
          "content": "示例评论",
          "is_mine": false
        }
      ],
      "media_truncated": false,
      "interactions_truncated": false
    }
  ],
  "next_cursor": "12345678901234567890",
  "has_more": null,
  "snapshot_complete": true,
  "snapshot_source": "network",
  "missing_ids": [],
  "raw_count": 1,
  "truncated": false
}

下一步: preparing/pending继续查询同一编号;succeeded读取业务结果;failed看error;unknown尤其write_accepted=true时禁止自动重新写入。

运行能力与视频准备诊断:/debug/moments_probe

{}同步读取实现标识、hooks、配置和operations,不刷新、不下载、不发布。传video及可选thumb则异步检查完整下载、视频元数据与封面,仍不发布,成功后清理本次临时资源。

参数 类型 要求 含义
request_id string 可选 可选原任务关联标识,最多128个UTF-16单位;命令通道取外层request_id。不是持久幂等键。
video string 可选 传入后异步检查视频,不发帖;省略则同步返回能力和状态快照。
thumb string 可选 选填封面;仅与video一起使用,省略自动生成。

运行时能力与任务状态

curl --request POST 'http://192.0.2.10:19088/debug/moments_probe' --header 'Content-Type: application/json' --data-raw '{}'

视频下载与解码诊断(不发布)

curl --request POST 'http://192.0.2.10:19088/debug/moments_probe' --header 'Content-Type: application/json' --data-raw '{"video":"https://example.com/video.mp4"}'

结果字段示例(同步返回):

{
  "ok": true,
  "implementation_revision": "moments_20261016_upload_v1",
  "media_upload_supported": true,
  "text_limit": 2000,
  "video_duration_limit_seconds": 300,
  "operations": []
}

传video时为异步操作,最终status=succeeded, probe_only=true, media_ready=true, accepted=false, write_accepted=false, server_confirmed=false。探针中的text_limit和video_duration_limit_seconds只是示例数值,实际以当前配置为准。

下一步: 视频准备探针通过后,如需发布,显式调用publish;探针没有创建可供media/file读取的朋友圈资源。

准备媒体并可主动上传:/moments/media/download

传sns_id和本帖media[].mid。省略upload为本地读取模式;提供upload则手机在下载、解密/复用缓存后主动上传到指定后端。只支持普通图片和视频朋友圈,不支持视频号、链接附件。

参数 类型 要求 含义
sns_id string 必填 目标动态的 sns_id,取自列表、详情或发布结果。非零 UInt64 十进制字符串,最大 18446744073709551615;不能提交 JSON 数字。
media_id string 必填 本动态media[]中mid原值,不能传URL或数组下标。
request_id string 可选 可选原任务关联标识,最多128个UTF-16单位;命令通道取外层request_id。不是持久幂等键。
upload object 可选 手机出站上传目标;只有上传完成整个操作才成功。省略此对象沿用本地读取。

远程后端:手机主动上传

curl --request POST 'http://192.0.2.10:19088/moments/media/download' --header 'Content-Type: application/json' --data-raw '{"sns_id":"12345678901234567890","media_id":"example-media-id","upload":{"url":"https://upload.example.com/uploads/22222222-2222-4222-8222-222222222222","resource_id":"22222222-2222-4222-8222-222222222222","method":"PUT","headers":{"Authorization":"Bearer REPLACE_WITH_SHORT_LIVED_TOKEN"}}}'

本地模式:手机临时文件

curl --request POST 'http://192.0.2.10:19088/moments/media/download' --header 'Content-Type: application/json' --data-raw '{"sns_id":"12345678901234567890","media_id":"example-media-id"}'

上传模式最终结果(server_confirmed=false正常):

{
  "ok": true,
  "status": "succeeded",
  "operation_id": "11111111-1111-4111-8111-111111111111",
  "request_id": "demo-request-001",
  "action": "media/download",
  "accepted": true,
  "write_accepted": false,
  "server_confirmed": false,
  "revision": 1,
  "error": "",
  "sns_id": "12345678901234567890",
  "media_id": "example-media-id",
  "media_ready": true,
  "delivery": "upload",
  "upload_completed": true,
  "upload_http_status": 201,
  "upload_outcome_unknown": false,
  "resource_id": "22222222-2222-4222-8222-222222222222",
  "content_type": "image/jpeg",
  "file_bytes": 297446,
  "cached": true,
  "source": "wechat_native"
}

省略upload时的本地模式结果:

{
  "ok": true,
  "status": "succeeded",
  "operation_id": "11111111-1111-4111-8111-111111111111",
  "request_id": "demo-request-001",
  "action": "media/download",
  "accepted": true,
  "write_accepted": false,
  "server_confirmed": false,
  "revision": 1,
  "error": "",
  "sns_id": "12345678901234567890",
  "media_id": "example-media-id",
  "media_ready": true,
  "delivery": "local",
  "content_type": "image/jpeg",
  "file_bytes": 297446,
  "cached": true,
  "source": "wechat_native",
  "media_url": "/moments/media/file/11111111-1111-4111-8111-111111111111",
  "expires_at_ms": 1775000600000
}

下一步: 远程后端推荐upload模式:等upload_completed=true后,按后端自分配的resource_id读取后端文件;无需访问手机HTTP。省略upload时才使用返回的media_url。

本地模式读取文件:GET /moments/media/file/{operation_id}

只有省略upload且本地媒体准备成功后才能使用。远程后端使用主动上传,不需要访问此入口。media_url为相对路径,拼接手机HTTP基址;operation_id为这次媒体准备的UUID,不是sns_id。链接最多10分钟,切号、重启、操作表淘汰、微信清缓存可提前失效。

curl --request GET 'http://192.0.2.10:19088/moments/media/file/11111111-1111-4111-8111-111111111111' --output preview.jpg

这是二进制响应,按Content-Type选择文件格式。无Range返回200整文件;Range单段返回206,支持bytes=0-65535、bytes=65536-、bytes=-65536;无效/越界/多段返回416与Content-Range: bytes */文件总长。非法UUID为400;未授权403;未就绪/过期/账号切换/缓存失效404。读取不触发下载,不支持任意手机文件路径。

常用业务按这个顺序调用

目标 调用顺序
获取最新好友动态 list → 等本次完成 → items
采集当前可见历史 list最新页 → 保存并去重 → next_cursor请求下一页 → 逐页等待;不能一个pending未完成就抢同范围下一页
获取指定用户历史 user带wxid → 等结果 → 同wxid加next_cursor翻页
回复评论 detail → comments选他人评论 → comment带reply_comment_id → 等完成 → detail更新显示
发布后修改范围 publish → 等服务器sns_id → permissions/update(type=post) → 等完成 → permissions/query(type=post)
删除刚发布动态 publish → 等服务器sns_id → delete → 等完成
远程读取图片/视频 list/detail取sns_id和mid → 后端准备上传目标 → media/download带upload → 等upload_completed → 从后端按resource_id读取
诊断发布视频 probe带video → 等media_ready → 需要发布时再显式publish,不会自动发帖

15. 收藏

用户已确认收藏功能在微信 8.0.80 验证通过;当前响应中的插件完整版本以设备实际返回为准。历史 0.8.79-13 曾用于早期收藏验证,不作为当前接入的版本条件。

本节请求发送到手机内置 HTTP 服务。示例地址 192.0.2.10:19088、收藏 ID、微信 ID 和游标均为占位值,请替换为实际值。所有 JSON 响应还包含 version:"8.0.80-2"。

功能 HTTP 路径
分页读取收藏 POST /favorites/list
发送指定收藏 POST /favorites/send
删除指定收藏 POST /favorites/delete

收藏参数严格校验,不适用本文其他接口的宽松类型转换、字符串自动裁剪或目标别名规则。

POST /favorites/list:最新在前的游标分页

参数 类型 必填 说明
limit integer 否 默认 50,范围 1–100;不接受数字字符串、布尔值或非整数
refresh boolean 否 默认 false,读取本机已同步内容;true 先等待微信同步及正文补齐,再返回第一页。只允许用于首请求,cursor 须省略或为空字符串
cursor string 否 上一页返回的 next_cursor,最多 128 个字符;首请求省略或传空字符串

顺序为最新收藏在前、最早收藏在后,当前实现按本机递增的 local_id 从大到小扫描。下一页继续向更早的 ID 读取,不要按 fav_id 的字符串大小或 create_time 自行重排后再推算游标。

分页由插件控制,底层读取微信本地收藏库;微信原生同步分批与对外分页是两层机制。首次建议 refresh:true,后续页只带 limit、cursor,直到 has_more:false。

  • 单页最多返回 limit 条;扫描和正文预算可能使一页不足 limit,甚至 items:[] 但 has_more:true。是否继续以 has_more 为准,继续时原样使用本页 next_cursor。
  • has_more:true 表示还有本地 ID 范围未扫描,不保证下一页一定有条目。结束时 next_cursor 为空字符串。
  • 游标绑定当前账号和登录周期,最长保留 30 分钟;内存最多保存 256 个游标,满额时旧游标也可能提前失效。账号切换、微信重启或游标失效后重新从第一页获取。
  • 第一页固定本轮扫描的最大本地 ID,翻页期间新收藏不插入本轮结果;要看新增项,重新请求第一页。期间删除、编辑或同步仍可能改变已有内容,这不是不可变快照。
  • 不支持 page、offset、排序参数、总数查询或一次返回全部。ID 有空洞,不能用返回条数推算下一页。

首次刷新并读取:

curl --max-time 60 --request POST 'http://192.0.2.10:19088/favorites/list' \
  --header 'Content-Type: application/json' \
  --data-raw '{"limit":50,"refresh":true}'

下一页(把 cursor 替换为上一页的 next_cursor):

curl --max-time 60 --request POST 'http://192.0.2.10:19088/favorites/list' \
  --header 'Content-Type: application/json' \
  --data-raw '{"limit":50,"cursor":"11111111-1111-4111-8111-111111111111"}'

刷新成功示例(为展示结构,示例只保留一条):

{
  "version": "8.0.80-2",
  "ok": true,
  "account_id": "wxid_self_example",
  "sync_state": "completed",
  "items": [
    {
      "fav_id": "123456",
      "local_id": "801",
      "type": 1,
      "title": "",
      "description": "收藏的示例文本",
      "url": "",
      "create_time": 1792112400,
      "update_time": 1792112400,
      "tags": [],
      "content_state": "ready",
      "forward_state": "ready",
      "block_reason": "",
      "data_list": [],
      "content_truncated": false
    }
  ],
  "has_more": true,
  "next_cursor": "11111111-1111-4111-8111-111111111111"
}

收藏列表结果字段

字段 类型 含义
account_id string 当前登录账号的微信 ID
sync_state string 本次 refresh:true 成功后为 completed;未请求刷新为 not_requested,不代表账号从未同步
items array 本页收藏,按本地 ID 递减排列
has_more / next_cursor boolean / string 是否还有扫描范围及继续读取的游标

items[] 的字段:

字段 类型 含义
fav_id string 微信收藏 ID;发送、删除使用此值。可能为 "0" 的未就绪条目不能用于这两个操作
local_id string 本机数据库 ID,仅用于本地排序,不可替代 fav_id
type integer 微信原生收藏类型;3 为语音,当前不支持转发语音收藏
title / description / url string 当前可读取的标题、正文或说明、链接;文本收藏正文在 description,缺失时为空字符串
create_time / update_time number 微信原生 srcCreateTime / updateTime,Unix 秒时间;不是翻页位置
tags string[] 可读取的文本标签
content_state string ready 已解析;metadata_pending 未同步或未解析完成;invalid 正文解析失败
forward_state string ready 当前可进入转发;needs_download 转发前需要原生补齐附件;forbidden 禁止转发;unknown 尚不能确定
block_reason string 不可转发的原因,可能为空
content_truncated boolean 正文、标签或嵌套内容触及保护上限,不能把已返回内容视为完整正文
data_list array 复合收藏的嵌套内容摘要,结构见下表

data_list[] 字段为 data_id(string)、data_type(integer)、title、description、format(string)、size(number,字节)、duration(number,微信原生值,单位依类型而定)、resource_state(local / remote / missing / unknown)和可递归的 data_list。资源状态仅描述微信本机可用情况,不提供可下载地址;data_id 不能用于发送或删除收藏。

列表不主动下载媒体。返回内容有每页正文预算、单字段长度、标签数量和嵌套节点保护;content_truncated 与分页的 has_more 含义不同。当前收藏能力只包含列表、发送和删除,没有独立的收藏详情、附件下载或任务查询接口。

POST /favorites/send:发送到好友或群

参数 类型 必填 说明
request_id string HTTP 必填;命令使用外层 调用方生成的业务请求标识,1–128 字符,不含首尾空白或控制字符
fav_id string 是 列表返回的收藏 ID,ASCII 十进制字符串,范围 1–4294967295,不允许前导零
receiver string 是 完整好友微信 ID,或含 @chatroom 后缀的完整群 ID;1–128 字符,不含首尾空白或控制字符

目标只使用 receiver,不支持另传 wxid、roomid、room_id 或接收人别名。好友须为当前账号可用的普通好友;群须仍有当前账号在群内。也支持当前账号自身及 filehelper。

正文须已解析且微信允许转发,语音收藏不支持。若原生转发要求附件,插件会让微信补齐所需资源并等待,可能增加耗时;这不提供独立的附件下载接口。列表的 forward_state 是读取当时的检查结果,发送时会再次检查。

curl --max-time 60 --request POST 'http://192.0.2.10:19088/favorites/send' \
  --header 'Content-Type: application/json' \
  --data-raw '{"request_id":"fav-send-demo-001","fav_id":"123456","receiver":"wxid_friend_example"}'

群目标仅将 receiver 替换为完整群 ID,例如 12345678901@chatroom。

HTTP 200 示例:

{
  "version": "8.0.80-2",
  "ok": true,
  "status": "accepted",
  "server_confirmed": false,
  "request_id": "fav-send-demo-001",
  "fav_id": "123456",
  "receiver": "wxid_friend_example"
}

HTTP 400、发送结果未知示例:

{
  "version": "8.0.80-2",
  "ok": false,
  "status": "unknown",
  "server_confirmed": false,
  "request_id": "fav-send-demo-001",
  "error_code": "SEND_RESULT_UNKNOWN",
  "error": "收藏操作超时,勿自动重发"
}

POST /favorites/delete:等待服务器确认删除

参数 类型 必填 说明
request_id string HTTP 必填;命令使用外层 业务请求标识,格式与发送相同
fav_id string 是 列表返回的收藏 ID,范围和格式与发送相同;不可传 local_id 或 data_id

删除的是当前登录账号的微信收藏,会进入微信原生同步删除流程。仅在微信服务器对该收藏返回明确成功后才返回 deleted。删除不要求收藏正文已解析、可转发或附件已下载。

ok:true、status:"deleted"、server_confirmed:true 三者同时成立才表示服务器确认删除。收藏已从列表消失、原生方法接收请求或本地待删除,都不能单独证明云端已删除。

curl --max-time 60 --request POST 'http://192.0.2.10:19088/favorites/delete' \
  --header 'Content-Type: application/json' \
  --data-raw '{"request_id":"fav-delete-demo-001","fav_id":"123456"}'

HTTP 200、服务器确认删除:

{
  "version": "8.0.80-2",
  "ok": true,
  "status": "deleted",
  "server_confirmed": true,
  "request_id": "fav-delete-demo-001",
  "fav_id": "123456"
}

HTTP 400、删除结果未知:

{
  "version": "8.0.80-2",
  "ok": false,
  "status": "unknown",
  "server_confirmed": false,
  "request_id": "fav-delete-demo-001",
  "fav_id": "123456",
  "error_code": "DELETE_RESULT_UNKNOWN",
  "error": "等待收藏删除确认超时,微信队列可能继续处理,请勿自动重新提交"
}

三项接口业务 ok:true 时 HTTP 200,业务失败或结果未知为 HTTP 400;授权失败仍按公共约定返回 HTTP 403。失败时保留 error_code、status 等诊断字段。

等待、幂等与错误处理

收藏接口采用单次调用等待结果,不返回需要另行轮询的 operation_id,也不产生专门的收藏完成事件。列表无刷新时直接读取本地;刷新约 20 秒、删除约 20 秒、发送准备及提交约 40 秒业务期限,另有约 45 秒后台等待保护。客户端业务结果等待建议至少 60 秒;代理和后端也需允许该时长。HTTP 的请求接收超时和命令通道的网络超时不是这段业务等待时长。

发送成功返回的 accepted 表示收藏已进入微信本地原生转发链路,没有微信服务器送达确认,所以 server_confirmed:false 是预期值。不要据此判为失败或自动重发;接口也不保证接收方已收到或已读。发送和删除的 unknown 都表示结果不能确认,HTTP 超时、断线或命令结果未收到也不能据此认定操作未执行。

  • 对已登记的同一发送或删除操作,相同账号和登录周期内,相同 request_id 与相同参数会复用原结果;仍在处理中返回 REQUEST_IN_PROGRESS,不重复提交。相同 ID 改参数返回 REQUEST_ID_CONFLICT。参数校验等登记前失败不占用幂等记录。
  • 发送和删除各最多保留 512 条内存幂等记录;满额拒绝新请求,不通过淘汰旧记录再次执行。微信重启、账号或登录周期变化后记录失效,后端仍需持久保存业务请求及结果。
  • 相同 ID 返回已有结果并不是重新查询微信最终状态。已经返回 unknown 时,不要通过更换 ID 自动重发或重删,先人工核实微信中的实际结果。
  • 当前同一账号只允许一个等待中的发送、一个等待中的删除;同一收藏的发送准备与删除互斥。收藏删除后列表会跳过本地待删除项,但列表缺项不能代替服务器确认。

三种接入方式使用相同业务 error_code。列表失败可不含 status;发送、删除通常返回 failed 或 unknown。优先按错误码分支,不要精确匹配中文错误文案。

error_code 含义与处理
INVALID_ARGUMENT 参数名、类型或范围不合法;收藏采用严格校验,拒绝未支持的字段
ACCOUNT_CHANGED 未登录、账号或登录周期已变化;重新确认账号,重取列表和游标
FEATURE_DISABLED 插件关闭,或发送/转发开关关闭
NATIVE_API_UNAVAILABLE 当前微信原生方法、回调或签名不可用,检查插件与微信版本
FAVORITES_SYNC_BUSY / FAVORITES_SYNC_FAILED / FAVORITES_SYNC_TIMEOUT 刷新正在进行、失败或超时;失败可能带 sync_diagnostics,没有返回本次“刷新完成”的列表
FAVORITE_NOT_FOUND 本机无法找到该收藏或已删除;删除时不能据此认定云端删除成功
FAVORITE_METADATA_PENDING 发送所需正文未就绪或解析失败,先刷新收藏列表
FAVORITE_NOT_FORWARDABLE 微信禁止转发,如语音收藏,原因见 error
FAVORITE_DOWNLOAD_FAILED / FAVORITE_DOWNLOAD_TIMEOUT 发送准备时所需资源补齐失败或超时
NATIVE_CONVERSION_FAILED / SEND_FAILED 原生消息转换失败或转发取消;是否已经进入提交仍看 status
TARGET_NOT_FOUND / TARGET_UNAVAILABLE 目标不存在、不可用、不是普通好友或当前账号不在群内
FAVORITES_SEND_BUSY / FAVORITES_DELETE_BUSY / FAVORITES_OPERATION_BUSY 有在途操作或同一收藏操作冲突,先等已有操作结果
REQUEST_IN_PROGRESS / REQUEST_ID_CONFLICT / IDEMPOTENCY_CAPACITY 同一请求仍在处理、ID 与参数冲突或本登录周期幂等记录已满
FAVORITE_DELETE_PENDING 收藏已在微信删除队列中,返回 unknown,不会再次提交
SEND_RESULT_UNKNOWN / DELETE_RESULT_UNKNOWN 已提交或等待超时后结果未知;不要自动重新提交

删除未知响应可能额外包含 native_error_code,表示等待期间观察到的微信原始错误码;微信原生队列可能继续重试,不能只用它推导最终成功或失败。


16. 公众号

公众号五项支持 HTTP、长轮询和 WebSocket,订阅号与服务号统一管理。公众号相关业务已由用户在微信 8.0.80 验证通过。目标必须使用真实公众号 username,不接受昵称或 alias,也不依赖 gh_ 前缀判断类型。下方示例均为虚构。

命令 HTTP 路径(均为 POST) 必需参数 可选参数
official_account_search /official_account_search keyword —
official_accounts /official_accounts — type、keyword、limit、offset
official_account_follow /official_account_follow id —
official_account_unfollow /official_account_unfollow id —
official_account_articles /official_account_articles id limit、cursor

三种通道使用相同参数及业务语义。参数采用严格类型校验,未知字段报 INVALID_ARGUMENT;整数不接受数字字符串或布尔值。需正常授权和登录;搜索、列表、文章查询不受发送总开关限制,关注/取关需要开启该开关,关闭时报 SEND_DISABLED。

已关注列表

{"type":"all","keyword":"","limit":100,"offset":0}

所有参数可省略。type 支持 all(默认)、subscription、service,区分大小写;keyword 是按账号、展示名、昵称、备注、alias 做不区分大小写的本地包含匹配。limit 默认 100、范围 1–1000;offset 默认 0、范围 0–4294967295。

返回 status:"ok"、type、keyword、items、total、limit、offset、has_more。total 是筛选后的数量;按展示名和账号排序,偏移超出范围时返回空页。每项沿用联系人摘要中的 account_id、display_name、nick_name、remark、alias、avatar_url 等字段,并增加 account_type(subscription/service)及 is_followed:true。这是本机已同步的名单,关注/取关后的关系可能延迟更新。

未登录返回 ACCOUNT_UNAVAILABLE,联系人尚未就绪返回 CONTACTS_NOT_READY,不能把失败当作空名单。它不是全网公众号搜索。

公众号关键词搜索

{"keyword":"示例"}

调用 official_account_search(HTTP 为 POST /official_account_search),仅接受 keyword 字符串,去除首尾空白后长度为 1–256 个 UTF-16 代码单元。输入公众号名称、微信号或关键词,联网返回微信原生首批候选,支持发现未关注公众号。

成功返回 status:"ok"、keyword、items、returned_count 和 request_submitted;取得原生返回码时包含 native_ret。候选复用联系人摘要中的 account_id、display_name、nick_name、alias、avatar_url 等字段,增加 account_type(本地已知时为 subscription/service,未取得为 null)与 is_followed(本地当前关注关系,可能延迟同步)。contact_found 仅表示本地联系人是否存在;未缓存的联网候选仍会返回。保留微信顺序并按真实 username 去重。无匹配时为 ok:true、items:[]、returned_count:0;超时、断网和微信业务错误不能当作无结果。

选中候选后,将其 account_id 作为 official_account_follow 的 id,例如 {"id":"official_account_example"}。搜索不会自动关注,也不受发送开关限制。它仅返回首批候选,不支持 limit、offset、cursor、page,不返回 total 或 has_more;匹配范围、排序及条数由微信决定。

约 30 秒业务超时,客户端等待建议至少 40 秒。

响应包含 search_diagnostics:当前 request_cgi 为 719,has_content 表示是否取得非空 JSON,json_byte_count 为其 UTF-8 字节数,json_ret 为 JSON 业务状态,section_count 为结果分组数。raw_item_count、parsed_item_count、contact_item_count、missing_username_count、duplicate_count 用于定位候选解析;missing_contact_count、unsupported_type_count 为旧诊断保留字段,当前为 0。native_business_type 为请求的公众号类型 1,native_continue_flag、native_offset 仅用于诊断,不开放分页。原生错误、JSON 业务错误、缺失内容或格式不兼容均返回失败,不能当成无匹配;只有有效成功的空列表才返回 ok:true、items:[]。诊断从开始原生请求时即可出现,不包含原始 JSON 或账号凭据。分组格式不兼容时,额外返回 invalid_section_index(从 0 开始)和 invalid_section_structure,只包含字段名、类型及数量;first 表示数组首项结构,encoded_json 表示字符串内 JSON 的结构。结构诊断最多 6 层、128 个节点,每个对象最多 64 个字段,truncated 表示截断;不输出字段值或原始 JSON。

关注与取消关注

两项均只传 {"id":"official_account_example"}。关注会先核对目标身份,再走公众号关注流程;返回单次结果,无需查询任务。

操作 status ok 含义
关注 already_followed true 本地已关注,request_submitted=false
关注 followed true 原生成功回调,且本地已观察到关注
关注 pending_sync true 原生成功回调,本地关系尚未同步;is_followed=false 不代表关注失败
关注 unknown false 已调用原生关注入口,尚无确定结果;先查列表,不自动重发
关注 timeout false 前置资料查询等阶段超时,尚未调用关注入口
取关 already_unfollowed true 本地已无关注关系,request_submitted=false,不重复清理
取关 submitted true 本地流程及同步提交已执行,request_submitted=true;未确认服务器最终结果
取关 unknown false 原生调用中发生异常,可能已有副作用,request_submitted=null
两项 failed false 参数、前置校验或微信业务失败,查看错误码及中文错误

响应包含目标 account_id,并按取得的信息返回 is_followed、request_submitted。is_followed 只表示本地观察值,未知可为 null 或省略;校验失败时也可省略目标字段。关注无回包时 native_invoked=true、request_submitted=null,不能视为确认提交;收到本次回包才可标为 true。profile_request_submitted=true 只表示前置资料查询已提交。

取关可能清理对应本地会话、聊天消息和其他关联信息。 进入原生取关调用后返回 chat_history_may_be_deleted=true;submitted 后本地 is_followed 仍可能暂为 true。结果未知时先查询关注关系,避免重复清理。

同一公众号仍在关注时返回 OPERATION_IN_PROGRESS;搜索、关注及文章请求合计最多同时保留 16 个,超出返回 TOO_MANY_REQUESTS。搜索、关注与文章查询整次约 30 秒超时、约 32 秒等待保护,客户端等待建议至少 40 秒。

历史文章按篇数批量续取

{"id":"official_account_example","limit":100}

limit 默认 100,范围 1–1000,按多图文展开后的文章篇数计数。插件自动连续读取微信原生小页并合并,最多返回指定篇数;不支持 page、page_size、offset,不提供历史总文章数,也不提供完整正文。

成功返回以下字段:

字段 类型 含义
status string ok
account_id string 目标公众号 username
limit integer 本次最多返回篇数
returned_count integer 等于 items.length,不超过 limit
items array 本批展开并合并后的文章
has_more boolean 仍有缓存余量,或微信原生历史尚未结束
next_cursor string/null 有后续时原样传回;全部结束时为 null
request_submitted boolean 本次是否提交过微信原生资料请求;仅使用缓存余量时为 false

每篇文章包含 account_id、app_msg_id(十进制字符串)、item_index(原生篇目位置)、title、digest、cover_url、url、author、publish_time(Unix 秒,未知为 null)、is_paid(boolean/null)。account_id + app_msg_id + item_index 共同定位文章;付费标记不能证明当前账号拥有阅读权限。

需要更早历史时,传入上一批的游标:

{"id":"official_account_example","limit":100,"cursor":"上一批返回的next_cursor"}

原生一页超过本批额度的文章会随游标保留,下一批先返回余量,不跳篇。微信已经结束但缓存未取尽时 has_more 仍为 true;空原生页会继续翻,不等于历史结束。成功不足 limit 时表示已到微信允许展示的末尾。整批失败返回 ok=false,不把部分结果伪装成完整成功;在游标有效期内可从原输入游标重试读取,或降低 limit。

cursor 可省略或传空字符串,从最新文章开始;不能传 null。它是进程内不透明 token,绑定当前账号、登录会话和目标公众号,单个 token 从生成起有效 10 分钟;全局最多保留 128 个,超出时淘汰最旧者。切换账号/会话、重启插件都会使旧游标失效,返回 INVALID_CURSOR 后应从最新文章重新读取。

错误、账号变化与发送文本

错误沿用中文 error 和机器可读 error_code。常见错误包括 INVALID_ARGUMENT、INVALID_ACCOUNT_ID、INVALID_ACCOUNT_TYPE、ACCOUNT_UNAVAILABLE、CONTACTS_NOT_READY、NATIVE_API_UNAVAILABLE、REQUEST_NOT_STARTED、REQUEST_TIMEOUT、WECHAT_REQUEST_FAILED、RESPONSE_INVALID。文章另有 INVALID_CURSOR、ARTICLES_RESTRICTED、CURSOR_NOT_ADVANCING;同一请求期间账号或登录会话变化返回 ACCOUNT_CHANGED。失败时不保证有 items、has_more、next_cursor 等成功字段。

向公众号发送文本仍使用已有 send_message,将同一个 username 放入 receiver,例如 {"receiver":"official_account_example","content":"你好"}。沿用原发送结果与公众号私信权限限制,成功不代表对方已收到或已读。

HTTP 调用与结果

直接向手机发送 POST /official_account_articles,请求体使用上方 JSON;其他四项使用各自路径。业务成功和业务失败均为 HTTP 200,检查响应顶层 ok、status、error_code;授权失败沿用 HTTP 403。单次等待最终结果,不新增任务查询接口。

HTTP 响应中的 account_id 表示目标公众号。可导入同目录 微信机器人.apifox.json(资料未收录) 调试上述接口。


17. 状态查询与后台保活

GET /account_status

用途:查询当前登录账号的资料。免鉴权。

响应示例:

{
  "ok": true,
  "is_logged_in": true,
  "account_id": "wxid_self",
  "user_name": "wxid_self",
  "display_name": "测试账号",
  "remark": "",
  "alias": "",
  "nick_name": "测试账号",
  "avatar_url": "",
  "sex": 0,
  "province": "",
  "city": "",
  "signature": "",
  "mobile": "",
  "country": "",
  "email": "",
  "has_profile_data": true,
  "wechat_version": "8.0.80"
}

GET /debug/device_status(别名 GET /device_status)

用途:查询设备运行状态(机型与系统版本、内存、电量、热状态、前后台)。免鉴权。

响应示例:

{
  "ok": true,
  "ts_ms": 1780018858960,
  "version": "8.0.80-2",
  "build_marker": "webridge_build_20261106_settings_update_8080",
  "device": {
    "ios_version": "16.1.1",
    "device_model": "iPhone14,3"
  },
  "process_memory": {
    "phys_footprint_mb": 537.1,
    "resident_mb": 753.5,
    "internal_mb": 296.2
  },
  "system_memory": {
    "available_estimate_mb": 1411.6,
    "used_estimate_percent": 74.9,
    "physical_total_mb": 5618.6
  },
  "battery": { "percent": 89, "state": "unplugged" },
  "power": { "low_power_mode": false },
  "thermal": { "state": "nominal", "raw": 0 },
  "network": { "connected": true, "network_type": "wifi", "cellular_generation": "" },
  "application": {
    "state": "background",
    "foreground": false,
    "active": false,
    "background": true
  },
  "path": "/debug/device_status"
}
分组 字段 说明
顶层 ts_ms 快照时间(毫秒)
顶层 version / build_marker 插件版本与构建标记
device ios_version 设备 iOS 版本,如 16.1.1。变长格式(16.1 就是两段)。读取失败时为空串
device device_model 机型标识符,取自 uname 的 machine,如 iPhone14,3。插件不做商名映射,需要商名请自行映射;模拟器上可能是 arm64 / x86_64
process_memory 12 个字段 6 个字节值(resident_bytes、virtual_bytes、phys_footprint_bytes、internal_bytes、compressed_bytes、reusable_bytes)+ 对应的 6 个 *_mb 值。取不到时输出 0,字段恒在
system_memory ok 是否成功采集到系统内存
system_memory 24 个测量字段 page_size、physical_total_*、free_*、active_*、inactive_*、wired_*、compressed_*、speculative_*、purgeable_*、external_*、available_estimate_*(字节与 MB 双份)、used_estimate_ratio(0–1)、used_estimate_percent(0–100)、note
system_memory ⚠️ 采集失败时 只有 ok: false 和 error,上述 24 个字段全部不出现——你的解析代码必须容忍这种退化的响应
battery level / percent level 为 0–1,percent 为 0–100。读不到时值为 null(不是 0)
battery state unplugged / charging / full / unknown
power low_power_mode 是否低电量模式
thermal state / raw nominal / fair / serious / critical / unknown,及原始值
network connected 网络是否可达
network network_type wifi / cellular / none / unknown
network cellular_generation 5g / 4g / 3g / 2g / unknown;非蜂窝网络时为空串 ""
application state active / inactive / background / unknown
application foreground / active / background 由 state 推导的三个布尔量

⚠️ 内存字段请用字节版或 MB 版,不要自己换算:process_memory 和 system_memory 都同时提供字节与 MB 两份,MB 版是 字节 / 1024 / 1024。 ⚠️ system_memory 里的 available_estimate 是估算值(空闲 + 非活跃 + 推测 + 可回收),插件自己在 note 字段里也写了"仅作趋势参考"。


GET /debug/keepalive_status

用途:只查询当前保活、进程/系统内存、前后台状态、电量、温度、低电量模式和机型信息。免鉴权,无请求参数;不返回账号、授权凭据、业务队列或定位坐标。

调用范围:仅由调用方访问手机的本地 HTTP 服务。WS / 长轮询没有 keepalive_status 命令,继续使用已有 bridge_status,在 result 中读取带 background_keepalive_ 前缀的字段。完整设备状态仍用 /debug/device_status、/device_status 或 device_status 命令。

Invoke-RestMethod 'http://手机IP:19088/debug/keepalive_status' | ConvertTo-Json -Depth 8

顶层字段:ok、ts_ms、version、build_marker、path、keepalive、process_memory、system_memory、application、battery、thermal、power、device。内存、电量等复用设备状态采集;内存字段为精简版,system_memory.available_estimate_mb 仅供趋势参考。

精简进程内存含 resident_bytes/mb、phys_footprint_bytes/mb、internal_mb、compressed_mb、reusable_mb;系统内存含 ok、physical_total_mb、free_mb、available_estimate_mb、used_estimate_percent。精简版取不到的测量值填 0,系统采集失败时仍保留这些字段并返回 ok:false,不透传完整设备接口的 error;应先检查 system_memory.ok 再解释数值。

keepalive 复用已有 background_keepalive_* 诊断,但去掉字段名前缀。例如原来的 background_keepalive_strategy 对应这里的 keepalive.strategy;last_error 是音频等原有保活错误,定位错误单独看 location_last_error。

keepalive 字段 含义
enabled、audio_enabled、location_enabled 总开关与两个通道的配置;总开关默认关闭,音频默认开启、定位默认关闭。总开关关闭后两个子配置保留,可能仍为 true
strategy 后台有效通道为 audio、location 或 audio+location;degraded 表示检查定时器存在但没有已确认的有效通道;foreground 表示定位在前台运行;stopped 表示通道停止
active 当前处于后台,且音频正在播放或定位已收到本次启动后的有效回调;不等于系统保证持续运行
timer_active 本插件后台检查定时器是否存在;存在不等于系统正在调度
last_check_at 最近一次实际后台定时检查的 Unix 秒;读取接口不会推进这个时间
app_state、last_state_update_at 最近更新状态时的前后台枚举(0 活跃、1 非活跃、2 后台)及 Unix 秒;本地专用接口会刷新该快照时间
location_background_mode 当前宿主是否声明后台定位模式;缺失时不启动定位
location_authorization unknown、not_determined、denied、restricted、when_in_use、always;未创建定位管理器时为 unknown
location_accuracy_authorization full / reduced / unknown,不主动要求精确位置权限
location_updates_requested、location_active、location_paused 已请求定位、已收到本次启动的有效回调、收到系统暂停通知;前台也可能 location_active=true
location_wait_reason 见下方原因值;正常收到有效回调后为空串
location_last_error 最近定位错误中文说明;新一轮启动或有效回调时清除
location_started_at、location_last_callback_at、location_last_update_at 最近启动、收到回调、有效定位数据的 Unix 秒;未发生时为 0,后两项保留进程内历史
location_last_update_age_seconds、location_update_count 最近有效定位的年龄(未发生时 null)与进程内累计收到的数据条数(包括被拒绝的旧缓存样本);静止时回调频率由系统决定
audio_playing、audio_interrupted、audio_wait_reason 原有音频运行状态和中断等待原因
available_memory_bytes、footprint_bytes 当前进程剩余内存预算、进程物理占用;前者不等于系统空闲内存,后者对应 process_memory.phys_footprint_bytes
last_memory_trim_reason、last_memory_trim_count、last_memory_trim_at 最近一次共享消息缓存减负的原因、数量和时间;未发生时可能没有这些字段
stop_reason 最近一次停止音频和检查的历史原因;不能单凭它判断当前定位状态

location_wait_reason:disabled(配置关闭)、missing_background_mode(宿主未声明)、missing_usage_description(缺定位说明)、location_services_disabled(系统定位关闭)、permission_denied / restricted(权限不足)、waiting_foreground(需回前台启动)、waiting_permission(等授权)、waiting_fix(已请求,等本次有效数据)、paused(系统暂停)、location_error(更新失败)。

定位使用前台启动、后台延续的持续更新方式,关闭自动暂停,目标精度约一公里。请求微信已有的“使用 App 期间”权限,不调用“始终允许”授权请求。开启前会核对宿主声明;开启后有系统定位标识并增加耗电。停用定位通道或总开关会停止本插件自己的定位,回前台时保持定位以便下次转后台;微信原生位置功能不由本服务管理。

下例仅为双开且后台有效时的响应节选示意,不是真机回包;实际字段会随状态变化,ok:true 只代表查询成功:

{
  "ok": true,
  "version": "8.0.80-2",
  "build_marker": "webridge_build_20261106_settings_update_8080",
  "path": "/debug/keepalive_status",
  "application": { "state": "background", "foreground": false, "active": false, "background": true },
  "keepalive": {
    "enabled": true,
    "audio_enabled": true,
    "location_enabled": true,
    "active": true,
    "strategy": "audio+location",
    "timer_active": true,
    "audio_playing": true,
    "location_background_mode": true,
    "location_authorization": "when_in_use",
    "location_updates_requested": true,
    "location_active": true,
    "location_wait_reason": "",
    "location_last_error": ""
  }
}

最小测试顺序:

  1. 单定位:开总开关,关音频、开定位;前台等到 location_active=true,再锁屏采样。后台预期 strategy=location、active=true、audio_playing=false。
  2. 单音频:关定位、开音频,再转后台;预期 strategy=audio、active=true、location_updates_requested=false。
  3. 双开:前台开两路、等到有效定位,再锁屏;预期 strategy=audio+location。通话时音频让出,定位仍有效时可变为 location,挂断后观察是否恢复双开,不承诺固定恢复时长。
  4. 关闭总开关:两个子开关保留选择并置灰;预期 enabled/active/timer_active/audio_playing/location_updates_requested/location_active 均为 false,strategy=stopped。再次开启时按保留配置运行。

接口可绕过业务串行队列,但仍依赖微信主线程处理状态读取。查询会刷新可观察状态及内存,不启动通道、不推进 last_check_at。应结合不同时间的 last_check_at、定位回调时间和实际业务结果判断;静止时定位回调不保证每 10 秒到达,单次 HTTP 能应答或 location_active=true 都不能证明此前一直未挂起。两路同在微信进程,低内存导致进程结束时都会停止。

历史保活测试使用过 0.8.79-35 构建,该记录不代表当前设备版本。保活与专用诊断已由用户在微信 8.0.80 验证通过;长期锁屏、通话及低内存下的运行仍受系统调度影响。采样时点、音频中断字段和失败排查见 巨魔后台保活测试说明(资料未收录)。


GET /debug/bridge_status

用途:插件的完整诊断快照——包含内部运行状态、最近的 API 调用路径、发送诊断、队列计数等。免鉴权。

说明:

  • 响应内容随插件内部状态变化,字段很多且不稳定。
  • 用途是排障,不要依赖其中任何字段做业务判断。
  • 响应里额外带上 build_marker 和 listen_port,在确认"手机上的插件到底是哪个版本"时很有用。
  • 保活共享诊断使用 background_keepalive_ 前缀;只看保活和内存时可改用上面的 /debug/keepalive_status。WS / 长轮询保活排障仍使用 bridge_status 命令。

18. 调试与诊断接口

以下接口不建议在生产环境依赖,用于排查"某个能力在当前微信版本上还能不能用"。其中只读探针返回诊断信息;名称含 send/mock 的实测入口及原生坐标反查可能执行其明确说明的动作,调用前按对应参数与副作用判断。

能力不可用时按相关业务章节选择对应探针排查;探针成功只说明本次检查通过,不能代替业务调用或真机验收。

端点 用途
POST /debug/message_media_probe 查询媒体或已有 CDN 任务,不触发下载或发送;参数见媒体说明
POST /debug/location_geocode_probe 指定经纬度执行原生反查,不发送消息
POST /debug/quote_build_probe 引用消息构造能力探测
POST /debug/inline_mention_send 正文内联 @ 实测
POST /debug/signal_send_probe 小信号发送链路探测
POST /debug/pat_send_probe 拍一拍链路探测
POST /debug/red_packet_probe 红包领取链路探测
POST /debug/red_packet_detail_probe 红包详情链路探测
POST /debug/transfer_probe、GET /debug/transfer_probe 转账链路探测;带候选参数时使用 POST
POST /debug/transfer_latest、GET /debug/transfer_latest 查最近一笔转账
POST /debug/clear_gender_region_probe 清除性别地区探测
POST /debug/profile_nickname_probe 改昵称探测
POST /debug/image_send_probe 图片发送探测
POST /debug/emoji_send_probe 表情发送探测
POST /debug/voice_send_probe 语音发送探测
POST /debug/video_send_probe 视频发送探测
POST /debug/video_send_url_probe 视频 URL 发送探测
POST /debug/link_send_probe 链接卡片探测
POST /debug/file_send_probe 文件发送探测
POST /debug/file_send_url_probe 文件 URL 发送探测
POST /debug/revoke_probe 撤回探测
POST /debug/delete_friend_probe 删除好友探测
POST /debug/quit_group_probe 退群探测
POST /debug/rename_group_probe(别名 POST /debug/set_group_self_nickname_probe) 群昵称修改探测(改的是「我在本群的昵称」,不是群名)
POST /debug/set_group_name_probe 只读检查整个群聊名称修改能力;请求体只需 room_id
POST /debug/friend_add_probe 主动添加好友运行时与候选引用探测
POST /debug/friend_request_probe 好友申请处理探测
POST /debug/group_member_nickname_probe 群成员昵称变更事件探测
POST /debug/group_invite_member_probe 群邀请探测
POST /debug/kick_group_member_probe(别名 /debug/kick_group_members_probe) 踢人探测
POST /debug/message_probe 消息探测
POST /debug/mock_incoming 模拟一条收到的事件(用于测试回调链路)
GET /debug/quote_runtime_probe 引用运行时环境探测
GET /debug/image_runtime_probe 图片运行时环境探测
GET /debug/web_entry_probe Web 入口探测
GET /debug/web_dom_probe Web DOM 探测
GET /debug/contact_mgr_probe 通讯录管理器探测
POST /debug/contact_friend_probe 好友判定探测
POST /debug/forward_runtime_probe 转发运行时环境探测
POST /livephoto_probe 实况照片链路探测
POST /livephoto_diagnostics 实况照片诊断日志

POST /livephoto_diagnostics 响应:

以下为响应结构节选,数组中的 ... 表示省略内容,不能直接作为 JSON 解析:

{ "ok": true, "count": 3, "logs": [ ... ] }

POST /debug/location_geocode_probe

实际调用 MMLocatingCoordinateLogic.requestAddressByLocation:params:withCompletion:,测试指定坐标的微信反查结果。不会发送聊天消息,不需要 receiver;需要已授权并登录微信,不受发送开关限制。可能命中微信缓存,也可能发起网络反查;request_invoked:true 不能证明本次一定发出了网络请求。

{"latitude":23.012345,"longitude":113.123456}

参数校验、默认反查参数和最多 15 秒回调等待与发送接口共用。HTTP 200 表示取得可用文字,失败为 400;都应检查响应体 ok。

返回字段 说明
probe / message_sent 固定 true / false(进入原生反查流程的探针响应)
request_invoked / callback_received 是否调用原生入口、是否收到本次回调
selector_signature / signature_supported 原生运行时签名及 ABI 检查结果;通过时 signature_supported:true
native_params 原生默认参数,正常为 type:1, scene:0, language_scene:0
elapsed_ms / timeout_seconds 本次耗时与等待上限(15 秒)
native_result_class 成功回调的原生结果对象类型
title / address / title_source 按发送接口规则选出的文字与来源
fields 原生返回文字,包含 poi_name、nearest_poi_name、rough_address、rough_address_with_direction、address_description、city、route、detail;各项可能为空
error_code / error 插件错误分类与中文说明
native_error_domain / native_error_code / native_error_message 原生错误回调信息,仅原生失败时存在;可用于检查 code 3(零坐标)或 code 4(无地址/取消)

常见 error_code:INVALID_COORDINATE、NOT_LOGGED_IN、NATIVE_UNAVAILABLE、GEOCODE_FAILED、GEOCODE_EMPTY、GEOCODE_TIMEOUT、ACCOUNT_CHANGED。完成、失败或超时都会清理本次原生回调和扩展注册;迟到回调不会触发发送。

真机验证建议先运行探针,检查 callback_received、fields、title,再用相同坐标调用 /send_location。也可执行标准库验证脚本:

python tests/location_geocode_smoke.py --base-url http://<手机IP>:19088 --latitude 23.012345 --longitude 113.123456

该脚本先检查错误参数会被拒绝,再执行一次有效反查,默认不发送任何聊天消息。用户已提供一次真机成功反查结果:取得可用标题和详细地址、收到回调;可能命中缓存,不据此认定联网。实际位置发送、最终卡片展示及坐标对点仍需在安装修复包后真机验证。


19. 兼容与已移除接口

19.1 兼容别名

别名路径 等价于
/group/invite_member /invite_group_member
/profile/nickname /profile_nickname
/kick_group_members /kick_group_member
/device_status /debug/device_status
/debug/room_members /room_members(返回内容更详细)
/download_message_image /debug/download_message_image
/debug/profile/nickname_probe /debug/profile_nickname_probe(GET / POST)
/debug/group/invite_member_probe、/debug/group_invite_member_probe、/debug/invite_group_member_probe 同一邀请能力探针(POST)
/debug/set_group_self_nickname_probe、/debug/set_group_nickname_probe /debug/rename_group_probe(POST)

资料探针的 GET/POST 入口见账号资料;其他探针见诊断接口。Apifox 按主接口维护;同一处理逻辑的兼容路径与方法见对应接口说明,不要求为每个别名单独建项。

新接入请一律使用主路径,别名只为兼容历史调用方而保留。

19.2 已废弃但保留的图片接口

POST /upload_message_image

状态:已废弃,保留兼容。新接入请使用 POST /upload_message_media,继续传 message_id 和可选 upload_url,返回字段以统一媒体接口为准。

用途:把某条消息里的图片上传到你指定的地址(图片被动上传)。

字段 类型 必填 说明
message_id string ✅ 消息 ID
upload_url string — 你的接收地址。不传时会使用插件内置的默认上传端点(即插件与服务端之间约定的 upload_media 地址);两个都取不到才会返回 upload_url is required

成功响应:透传业务结果(含 uploaded 等字段)。

失败响应:400,且响应体直接采用业务结果对象,可能额外带 uploaded: false。

前置条件:发送开关必须开启,否则 400 且响应体带 uploaded: false。


POST /download_message_image(别名 /debug/download_message_image)

状态:已废弃,保留兼容,别名同样废弃。新接入请使用 POST /download_message_media,继续传 message_id,从 resolved_local_path 读取手机文件路径。

用途:让插件把某条消息里的图片下载到本地沙盒。

字段 类型 必填 说明
message_id string ✅ 消息 ID

成功响应:透传下载结果(含本地路径等字段)。

失败响应:400,响应体为业务结果对象或 {"ok": false, "error": "download_message_image failed", "message_id": "..."}。

19.3 已移除:会话已读

状态:已废弃且已移除,不保留兼容入口。 单个、批量、全部已读均不再支持,当前无替代接口;发送后自动已读功能及其设置项也已移除。

已移除路径 行为
/mark_session_read 业务入口已移除,不支持单个、批量或全部已读
/debug/mark_session_read_probe 探针已移除,不提供替代调用

POST /mark_session_read 通过通用前置校验后返回 HTTP 404:

{
  "ok": false,
  "error": "route not found",
  "build_marker": "当前构建标识",
  "method": "POST",
  "path": "/mark_session_read"
}

POST /debug/mark_session_read_probe 同样已废弃且已移除;通过前置校验后返回相同错误结构,path 为该探针路径。请停止调用,不要通过重试恢复已读功能。校验失败时仍按本篇通用鉴权和插件状态错误处理。


附录:常见接入问题

  1. 不要依赖 keep-alive——每个响应都会关闭连接。/events 等待结束应正常返回空数组;若在收到完整响应前连接中断,保留原游标并按退避策略重试。
  2. 不要把大文件 Base64 塞进 body——上限 1 MiB,请传路径或 URL。
  3. 判断成功要同时看状态码和 ok——有 200 + ok:false 的情况(offset_expired 即是)。
  4. send_message 的 @所有人 必须自己写进 content——插件不补。
  5. {{mention:wxid}} 解析不出昵称会整条失败——不是静默降级。
  6. send_music_card 缺参数会静默用默认值发出——要发自己的音乐,五个字段都要传。
  7. accept_friend_request 的 request_id 是业务参数,和命令信封的 request_id 同名不同义。
  8. 404 时看响应体里的 method / path 回显——能立刻发现路径拼错。
  9. /events 处理成功后再保存 next_offset——提前保存会在业务处理失败时跳过事件;同时必须按 event_id 去重(详见 4.2.4)。
  10. /events 明确返回 offset_expired 时必须恢复游标——用响应的 next_offset 继续并记录告警;其他错误保留游标。丢失的事件不会补发,缓冲默认只留 120 秒。
  11. /events 必须按本批 next_offset 续拉——积压超过 limit 时不要跳到 latest_offset + 1;has_more:true 表示本批之后还有已入队事件。
  12. 注意中文编码——事件含中文,Windows 终端或旧客户端可能按本地编码显示乱码;排错时先保存响应体,再按 UTF-8 查看。
以上内容来自已收录协议原文遇到问题?查看帮助

搜索开发文档

在接入总览与各模式协议中查找;结果保留对应模式和章节。

输入关键词开始搜索,例如 或 。