微信读书 API 文档

文档编号 04

04 - 微信读书 API 文档研究笔记

日期:2026-08-14
用途:个人动态页"阅读动态"模块数据来源(取代原 GitHub 动态)
接入方式:微信读书 Agent Gateway(个人 API Key)
相关代码:usr/themes/classic-22/inc/weread-client.php(客户端)、usr/themes/classic-22/inc/weread-activity.php(聚合与渲染)

认证方式

Authorization: Bearer WEREAD_API_KEY
Content-Type: application/json
  • API Key 存放在 config.inc.php 的 WEREAD_API_KEY(已在 .gitignore,不提交 Git)
  • 也可通过环境变量 WEREAD_API_KEY 提供(wereadApiKey() 优先取常量,其次取环境变量)
  • 注意:属于敏感凭证,维护文档中禁止出现真实值

Gateway 基本信息

项目内容
端点POST https://i.weread.qq.com/api/agent/gateway
请求版本skill_version: 1.0.4(可由 WEREAD_SKILL_VERSION 覆盖)
认证Authorization: Bearer WEREAD_API_KEY
超时连接 4s / 总超时 8s,curl_multi 并行批量请求

请求体格式(重要)

参数拍平到顶层,不要把参数包在 params 对象里,否则返回 errcode=-2003:

{
  "api_name": "/book/getprogress",
  "bookId": "3300035133",
  "skill_version": "1.0.4"
}

通用回包约定

  • 顶层 errcode 为 0 表示成功;非 0 为失败(如 -2003 参数格式错误 / 缺少必填参数)
  • 回包出现 upgrade_info 时表示需要升级 skill,本次请求失败
  • 客户端 wereadDecodeGatewayResponse() 已封装校验:HTTP 2xx + errcode==0 且无 upgrade_info 才算成功
  • 客户端 wereadBuildGatewayPayload() 内部正是用 array_merge($params, [...]) 把参数拍平到顶层

接口总览

api_name说明使用场景
/readdata/detail阅读数据统计(月度/年度等)第一波请求,params: {mode: monthly}
/shelf/sync同步书架,返回书架上的书籍列表第一波请求,无参数
/book/getprogress单本书阅读进度与时长的详细信息第二波请求,params: {bookId},候选池每本一个

/readdata/detail(月度统计)

请求:{"api_name":"/readdata/detail","mode":"monthly","skill_version":"1.0.4"}

返回 data 关键字段:

字段说明
totalReadTime本月总阅读时长,单位秒
readDays本月有效阅读天数
dayAverageReadTime按已过去自然日计算的日均时长,单位秒
readTimes每天阅读秒数映射({时间戳: 秒数})
readLongest[]本月阅读时长最长的若干本书(每项含完整 book 信息 + readTime + tags)
readStat[]"读过/读完/阅读/笔记"统计文案
preferBooks[]偏爱书籍(常读常新、近期偏爱、最沉浸等,按 type 区分)
preferCategory[]偏好分类(按分类聚合阅读时长)

注意:readLongest 只覆盖本月读得最多的少数几本,不等于"最近阅读"候选,不能作为展示过滤的唯一来源。


/shelf/sync(书架)

请求:{"api_name":"/shelf/sync","skill_version":"1.0.4"}

返回 data.books[] 单本书字段:

字段说明
bookId书籍唯一 ID
title书名
author作者
cover封面 URL(HTTPS)
deepLink微信读书跳转链接(weread.qq.com 域)
secret1 = 私密书籍
readUpdateTime最近阅读时间戳;<=0 表示未读
finishReading是否读完
updateTime / category其它信息

注意:shelf 单本书不包含阅读时长字段,时长必须靠 /book/getprogress 获取。书架书籍可能上百本,不能全量拉进度。


/book/getprogress(单本进度)

请求:{"api_name":"/book/getprogress","bookId":"3300035133","skill_version":"1.0.4"}

返回 data.book 关键字段:

字段说明
bookId书籍 ID
progress阅读进度百分比(0-100)
readingTime总阅读时长(秒),用于"总阅读时长"过滤
updateTime最近阅读时间戳(作为卡片 last_read_time)
chapterUid / chapterIdx当前阅读位置
recordReadingTime恒为 0,勿用(接口未返回真实值,早期误用导致过滤失效)

聚合与过滤逻辑(weread-activity.php)

  1. 第一波并行请求 /readdata/detail?mode=monthly + /shelf/sync。
  2. 过滤 books[].secret=1 的私密书籍与 readUpdateTime<=0 的未读书籍。
  3. 按 readUpdateTime 降序取最近 WEREAD_BOOK_CANDIDATE_LIMIT 本(默认 24)作为候选池。
  4. 第二波并行请求候选池每本的 /book/getprogress(curl_multi 并发,总耗时≈最慢单请求)。
  5. 过滤总阅读时长 < WEREAD_MIN_BOOK_READ_SECONDS(默认 1800 秒 = 30 分钟)的书;进度请求失败、无法确认时长的书同样过滤。
  6. 剩余按 readUpdateTime 降序取前 3 本展示;不足 3 本时有几本显示几本,0 本显示"暂无公开阅读记录"。

关键实现点

  • 时长过滤用 book.readingTime(总时长),不是 recordReadingTime。
  • 候选池 24 本保证"最近只点开几本书、真正读过的书排在更后面"时仍能凑满 3 本;实际数据下最近 24 本内通常有 4-6 本过 30 分钟。
  • 进度失败即 readingTime=0,在阈值过滤下被丢弃(候选池有兜底,不因单本失败回退显示 --)。
  • 隐私规则:私密/未读书籍在排序与请求前过滤;deepLink 仅接受 weread.qq.com 及其子域的 HTTPS。
  • 缓存:usr/cache/weread_activity.json(6 小时)与永久兜底 weread_activity_fallback.json。

可调配置(config.inc.php,均为可选)

define('WEREAD_API_KEY', '...');               // 必填,个人 API Key
define('WEREAD_SKILL_VERSION', '1.0.4');       // 可选,默认 1.0.4
define('WEREAD_MIN_BOOK_READ_SECONDS', 1800);  // 可选,展示书籍的最小总阅读时长(秒),默认 1800

请求示例

获取月度阅读统计

curl -s https://i.weread.qq.com/api/agent/gateway \
  -H "Authorization: Bearer <key>" -H "Content-Type: application/json" \
  -d '{"api_name":"/readdata/detail","mode":"monthly","skill_version":"1.0.4"}'

同步书架

curl -s https://i.weread.qq.com/api/agent/gateway \
  -H "Authorization: Bearer <key>" -H "Content-Type: application/json" \
  -d '{"api_name":"/shelf/sync","skill_version":"1.0.4"}'

查询单本进度(含总阅读时长)

curl -s https://i.weread.qq.com/api/agent/gateway \
  -H "Authorization: Bearer <key>" -H "Content-Type: application/json" \
  -d '{"api_name":"/book/getprogress","bookId":"3300035133","skill_version":"1.0.4"}'

注意事项

  1. 参数必须拍平到顶层:包在 params 里会报 errcode=-2003 参数格式错误。
  2. readingTime 才是总阅读时长;recordReadingTime 恒为 0。
  3. 进度请求按候选池并发(24 个 curl_multi),不是串行,不会 24 倍延迟;只在冷缓存刷新时发生(6 小时一次)。
  4. 回包出现 upgrade_info 或 errcode != 0 时本次刷新失败,回退读取 fallback 缓存。
  5. readdata/detail 里返回的 readLongest[] 只含本月读得最多的几本,不代表"最近阅读",勿用作过滤来源。
  6. 卡片 deepLink 只使用接口返回的 HTTPS 链接,host 必须为 weread.qq.com 或子域,不自行拼接。