ActivityWatch 0.14.1 API 使用详解
REST API 认证与信息/桶/事件/查询四大域端点全实测:心跳写入、聚合查询、导出备份与错误行为逐条照录。
ActivityWatch 0.14.1 API 使用详解
目标:系统讲清 ActivityWatch 0.14.1 的 REST API——认证方式、信息/桶/事件/查询四大域的端点、参数与错误行为,让读者能用 curl 或任意 HTTP 客户端完成"查状态、建桶、写心跳、聚合查询、导出备份"的全部运维动作。所有请求与响应均在 Ubuntu 22.04(22.04.5 LTS)+ aw-server v0.14.1(Python 版)实测采集,逐条照录。
一、环境信息
- 操作系统:Ubuntu 22.04(22.04.5 LTS,x86_64)
- 服务端:aw-server v0.14.1(Python/Flask 实现,API 基地址
http://localhost:5600/api/0) - 认证:示例开启
[server.auth] api_key = "q1w2e3r4"(演示口令,生产请换强随机值;开启方式与生效行为见《ActivityWatch 0.14.1 配置参数详解》5.6) - 客户端工具:系统 curl(本章唯一依赖,无需 SDK)
- 测试数据:桶
test-bucket(type=test),内含 3 条 not-afk/cli-test 心跳事件(创建过程见第五章) - 版本查询日期:2026-10-22(v0.14.1 为官方最新稳定版)
二、前置条件
- aw-server 运行中(systemd 托管),本机探活通过:
systemctl is-active aw-server
curl -s http://localhost:5600/api/0/info
active
{"hostname": "aw-server01", "version": "v0.14.1", "testing": false, "device_id": "a34e4cfc-7992-4c03-a7a2-7422da090665", "profile": "default"}
- 若服务端启用了 api_key,准备好鉴权头变量(本文后续示例统一用它):
H="Authorization: Bearer q1w2e3r4"
- 理解三个名词:bucket(数据桶,按采集来源划分的存储分区)、event(事件,时间戳+时长+data JSON)、canonical query(服务器内置的查询语言,在
/api/0/query/端点执行)。三者关系见《ActivityWatch 0.14.1 介绍与选型指南》第三章。
三、API 总览
| 项 | 说明 |
|---|---|
| 协议与风格 | HTTP REST,请求/响应均为 JSON(Content-Type: application/json) |
| 版本路径 | /api/0/(当前唯一版本前缀;另有旧版 /api/ 兼容路径,不建议新代码使用) |
| 认证 | 默认无认证;在 [server.auth] 设置 api_key 后,除 GET /api/0/info 与 OPTIONS 预检外全部要求 Authorization: Bearer <key> |
| 限流约定 | 无官方限流参数;watcher 心跳靠客户端合并(pulsetime)控制写入量,查询侧靠 query_cache 缓解重复计算 |
| 典型错误形态 | 校验失败返回 400 + {"errors": {...}, "message": "Input payload validation failed"};认证失败 401 + 提示 JSON;资源不存在 404 + 提示 JSON |
| Web UI | 与 API 同端口:http://localhost:5600/ 托管 aw-webui 单页应用 |
四大域端点速查(均在本章/第五章实测):
| 域 | 端点 | 方法 |
|---|---|---|
| 信息 | /api/0/info | GET |
| 桶 | /api/0/buckets/ | GET |
| 桶 | /api/0/buckets/<id> | GET / POST / DELETE(?force=1) |
| 桶 | /api/0/buckets/<id>/export | GET |
| 事件 | /api/0/buckets/<id>/heartbeat?pulsetime= | POST |
| 事件 | /api/0/buckets/<id>/events | GET |
| 事件 | /api/0/buckets/<id>/events/count | GET |
| 查询 | /api/0/query/ | POST |
四、认证与首次调用
开启 api_key 后的首次调用实测。不带认证头访问受保护端点:
curl -s http://localhost:5600/api/0/buckets/
{"message": "Missing or invalid API key. Set Authorization: Bearer <key> header."}
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:5600/api/0/buckets/
401
带正确认证头重试(本文演示口令 q1w2e3r4):
curl -s -H "Authorization: Bearer q1w2e3r4" http://localhost:5600/api/0/buckets/
{"test-bucket": {"id": "test-bucket", "created": "2026-10-22T16:14:56.717943+00:00", "name": null, "type": "test", "client": "aw-client-test", "hostname": "aw-server01", "data": {}, "last_updated": "2026-10-22T16:18:24.658000+00:00"}, "aw-watcher-afk_aw-server01": {"id": "aw-watcher-afk_aw-server01", "created": "2026-10-22T16:19:07.214904+00:00", "name": null, "type": "afkstatus", "client": "aw-watcher-afk", "hostname": "aw-server01", "data": {}}}
错误口令同样 401(实测 -H "Authorization: Bearer wrongkey" → 401,响应体同上提示 JSON)。信息端点恒为公开,无需认证(实测 200):
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:5600/api/0/info
200
五、各 API 域详解
5.1 信息域:GET /api/0/info
服务器健康检查与版本探测的标准端点(监控脚本探活用这个)。无参数:
curl -s -H "$H" http://localhost:5600/api/0/info
{"hostname": "aw-server01", "version": "v0.14.1", "testing": false, "device_id": "a34e4cfc-7992-4c03-a7a2-7422da090665", "profile": "default"}
字段解读:hostname 服务器主机名;version 服务器版本(Rust 实现带 (rust) 后缀,实测 Rust 版返回 "v0.14.1 (rust)");testing 是否 testing 实例;device_id 设备唯一标识(随数据目录生成,换库即变);profile 实例 profile 名(默认 default)。
5.2 桶域:/api/0/buckets
5.2.1 列出全部桶(GET /api/0/buckets/):见第四章回显,键为桶 ID,值含 created/type/client/hostname/data/last_updated。type 是桶的数据语义(如 afkstatus、currentwindow、浏览器扩展的 web.tab.current),做查询过滤时的依据。
5.2.2 查看单个桶(GET /api/0/buckets/<id>):
curl -s -H "$H" http://localhost:5600/api/0/buckets/test-bucket
{"id": "test-bucket", "created": "2026-10-22T16:14:56.717943+00:00", "name": null, "type": "test", "client": "aw-client-test", "hostname": "aw-server01", "data": {}}
5.2.3 创建桶(POST /api/0/buckets/<id>):请求体需 client/type/hostname 三个字段:
curl -s -H "$H" -X POST -H "Content-Type: application/json" -d '{"client": "aw-client-test", "type": "test", "hostname": "aw-server01"}' http://localhost:5600/api/0/buckets/test-bucket
{}
成功返回空 JSON {};创建后立即可在列表中看到(见 4 章)。重复创建同 ID 桶返回同为空 JSON(幂等)。
5.2.4 删除桶(DELETE /api/0/buckets/<id>?force=1):带保护机制——非 testing 模式必须加 ?force=1,否则拒绝。实测不带 force 的拒绝回显(注意状态码仍是 401):
curl -s -H "$H" -X DELETE http://localhost:5600/api/0/buckets/todel
{"message": "Deleting buckets is only permitted if aw-server is running in testing mode or if ?force=1"}
加 force 后真删(实测删除桶 todel,返回空 JSON,列表复查确认消失):
curl -s -H "$H" -X DELETE "http://localhost:5600/api/0/buckets/todel?force=1"
{}
curl -s -H "$H" http://localhost:5600/api/0/buckets/ | python3 -c "import sys,json; print(sorted(json.load(sys.stdin).keys()))"
['aw-watcher-afk_aw-server01', 'test-bucket']
⚠️ 注意:删除桶会连带删除其全部事件且不可恢复,生产上删除前先用 5.2.5 的导出接口备份。
5.2.5 导出桶(GET /api/0/buckets/<id>/export):桶定义 + 全部事件的 JSON(实测节选):
curl -s -H "$H" http://localhost:5600/api/0/buckets/test-bucket/export
{"buckets": {"test-bucket": {"id": "test-bucket", "created": "2026-10-22T16:14:56.717943+00:00", "name": null, "type": "test", "client": "aw-client-test", "hostname": "aw-server01", "data": {}, "events": [{"timestamp": "2026-10-22T10:05:00+00:00", "duration": 0.0, "data": {"status": "not-afk"}}, {"timestamp": "2026-10-22T10:00:00+00:00", "duration": 30.0, "data": {"status": "not-afk"}}]}}}
导出文件可直接作为备份;/api/0/buckets/export(不带桶 ID)导出全部桶。
5.3 事件域:心跳与读取
5.3.1 写入心跳(POST /api/0/buckets/<id>/heartbeat?pulsetime=):心跳是"某状态持续中"的信号;pulsetime(秒)声明本心跳的有效窗口,窗口内到达的同 data 心跳会与之前的事件合并(时长累加):
curl -s -H "$H" -X POST -H "Content-Type: application/json" -d '{"timestamp": "2026-10-22T10:00:00+00:00", "duration": 0, "data": {"status": "not-afk"}}' "http://localhost:5600/api/0/buckets/test-bucket/heartbeat?pulsetime=120"
{"id": 1, "timestamp": "2026-10-22T10:00:00+00:00", "duration": 0.0, "data": {"status": "not-afk"}}
合并行为实测:再发两条时间差 30 秒与 4.5 分钟的心跳(pulsetime 均为 120),随后查询聚合得到 duration 合计 30.0(相邻合并)与 merge_events_by_keys 合并后总时长 30.0(回显见 5.4.3)。客户端时间戳用 ISO 8601 带时区格式。
5.3.2 读事件(GET /api/0/buckets/<id>/events):
curl -s -H "$H" "http://localhost:5600/api/0/buckets/test-bucket/events?limit=5"
[{"id": 3, "timestamp": "2026-10-22T16:18:24.658000+00:00", "duration": 0.0, "data": {"status": "cli-test"}}, ...]
支持参数(见第六章约定):limit、starttime、endtime、orderby。过滤实测(限定起点后只返回 1 条且配了 limit=1):
curl -s -H "$H" "http://localhost:5600/api/0/buckets/test-bucket/events?starttime=2026-10-22T10%3A00%3A30%2B00%3A00&limit=1"
[{"id": 3, "timestamp": "2026-10-22T16:18:24.658000+00:00", "duration": 0.0, "data": {"status": "cli-test"}}]
5.3.3 事件计数(GET /api/0/buckets/<id>/events/count):
curl -s -H "$H" http://localhost:5600/api/0/buckets/test-bucket/events/count
3
5.4 查询域:POST /api/0/query/
查询域是 ActivityWatch 的分析核心:POST 一个 JSON,query 数组里是一段 canonical query 脚本,对 timeperiods 里每个时段各执行一次。
5.4.1 请求体字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| query | string 数组 | 是 | 查询脚本(多行合成一段执行,最后 RETURN 结果) |
| timeperiods | "start/end" 字符串数组 | 是 | 每个元素一个 ISO 8601 时段 |
| name | string | 否 | 查询命名(配 cache 用) |
| cache | bool | 否 | 是否使用服务端查询缓存 |
5.4.2 最小查询实测:
curl -s -H "$H" -X POST -H "Content-Type: application/json" -d '{"query": ["events = query_bucket(\"test-bucket\"); RETURN = events;"], "timeperiods": ["2026-10-22T00:00:00+00:00/2026-10-23T00:00:00+00:00"]}' http://localhost:5600/api/0/query/
[[{"data":{"status":"not-afk"},"duration":0.0,"id":1,"timestamp":"2026-10-22T10:00:00+00:00"}]]
返回值为数组的数组:外层对应 timeperiods(1 个时段),内层为 RETURN 的值。
5.4.3 聚合算子实测(merge_events_by_keys 按 data.key 合并相邻事件;sum_durations 求时长和):
curl -s -H "$H" -X POST -H "Content-Type: application/json" -d '{"timeperiods": ["2026-10-22T00:00:00+00:00/2026-10-23T00:00:00+00:00"], "query": ["events = query_bucket(\"test-bucket\"); merged = merge_events_by_keys(events, [\"status\"]); dur = sum_durations(events); RETURN = [merged, dur];"]}' http://localhost:5600/api/0/query/
[[[{"data":{"status":"not-afk"},"duration":30.0,"id":null,"timestamp":"2026-10-22T10:05:00+00:00"}],30.0]]
解读:内层 [merged, dur] = 合并后的事件(3 条相邻 not-afk 合成 1 条 30 秒)+ 总时长 30.0。带 name/cache 的调用实测(返回 [30.0],与上面 dur 一致):
curl -s -H "$H" -X POST -H "Content-Type: application/json" -d '{"query": ["events = query_bucket(\"test-bucket\"); RETURN = sum_durations(events);"], "timeperiods": ["2026-10-22T00:00:00+00:00/2026-10-23T00:00:00+00:00"], "name": "sum-test", "cache": false}' http://localhost:5600/api/0/query/
[30.0]
5.4.4 错误行为实测(两类高频错误):
缺 timeperiods → 400 校验错误:
curl -s -H "$H" -X POST -H "Content-Type: application/json" -d '{"query": ["events = query_bucket(\"test-bucket\"); RETURN = events;"]}' http://localhost:5600/api/0/query/
{"errors": {"timeperiods": "'timeperiods' is a required property"}, "message": "Input payload validation failed"}
脚本内语法/参数错误 → QueryParseException(实测 query_bucket 用了 limit=1 命名参数写法):
{"type": "QueryParseException", "message": "Expected , between arguments to query_bucket, got: =1"}
结论:query_bucket 的 limit 要用位置参数 query_bucket("<bucket>", 1),不能写 limit=1。常用算子速览:query_bucket(id, limit?) 取桶事件、filter_period_intersect 交集(如窗口事件剔除 AFK)、merge_events_by_keys(events, keys) 合并、sum_durations(events) 求和、concat_events_by_data 拼接——完整函数表见官方查询文档(参考链接)。
六、分页/过滤/排序通用约定
- 事件读取参数(
GET /api/0/buckets/<id>/events):limit(最大返回条数)、starttime/endtime(ISO 8601 时间过滤,URL 编码+为%2B)、orderby(排序键)、orderby_value(配合 orderby 的取值);不传 limit 时返回时段内全部事件,大桶务必带 limit(实测见 5.3.2); - 时间一律 ISO 8601 带时区(如
2026-10-22T10:00:00+00:00);省略时区的裸时间在不同端点行为不一致,统一带时区最稳; - 查询域无分页:
timeperiods切时段即天然"分批",需要大范围统计时按天/周拆时段循环调用; - 心跳去重:同 data 的连续心跳在 pulsetime 窗口内自动合并,调用方无需自己去重;窗口外到达的心跳生成新事件(5.3.1 实测:间隔 4.5 分钟的两条在 pulsetime=120 下生成了独立事件)。
七、常见问题(FAQ)
Q1:所有请求都返回 Missing or invalid API key?
服务端开了 api_key 而请求没带认证头(或口令不对)。补 -H "Authorization: Bearer <key>";只有 /api/0/info 与 OPTIONS 预检豁免。注意 5.2.4 的"删除未加 force=1"也以 401 形态返回,看响应体区分。
Q2:DELETE 桶返回 401 但响应体说 testing/force?
这是桶删除保护:非 testing 实例必须 ?force=1(实测回显见 5.2.4)。force 删除不可恢复,先 export。
Q3:timeperiods 到底怎么写?
"起/止" 的 ISO 8601 区间字符串,放进数组可一次给多个时段(如整周按天 7 个),响应外层数组与时段一一对应。实测缺失该字段返回 400 校验错误(5.4.4)。
Q4:查询脚本里怎么传桶 ID/字符串?
canonical query 里字符串用双引号;经 curl -d 传 JSON 时需转义为 \"(5.4.2 命令示例即此形态)。脚本语法错误返回 QueryParseException,按 message 定位。
Q5:有没有官方 Python/JS 客户端?
有:aw-client(Python,pip 包,其 CLI 六个子命令实测见《ActivityWatch 0.14.1 常用 CLI 命令与工具详解》第五章);浏览器扩展与 webui 走同一套 REST API。第三方语言按本文端点自封装即可——API 本身极简(增删查 + query)。
八、参考链接
- 官方 API 文档:https://docs.activitywatch.net/en/latest/api.html
- 官方查询语言文档:https://docs.activitywatch.net/en/latest/querying-canonical-events.html
- aw-server REST 层源码:https://github.com/ActivityWatch/aw-server
- aw-client(Python 客户端):https://github.com/ActivityWatch/aw-client
- 本专栏相关:《ActivityWatch 0.14.1 介绍与选型指南》、《Ubuntu 22.04 安装 ActivityWatch 0.14.1 指南》、《ActivityWatch 0.14.1 配置参数详解》、《ActivityWatch 0.14.1 常用 CLI 命令与工具详解》