Aptabase API 使用详解
Aptabase API 使用详解:认证/事件上报(单条+批量)/应用管理/面板统计四大域接口逐条实测(含真实请求与响应回显)、App-Key 与会话认证双轨制、错误码与通用约定,基于 main 镜像(2026-10-30)实测。
Aptabase API 使用详解
目标:给出 Aptabase 自托管实例的 HTTP API 全景与四大核心域(认证、事件上报、应用管理、面板统计)的逐条实测调用,读者可直接用 curl 完成账号、事件与面板数据的全部程序化操作。全部请求与响应均为 Ubuntu 22.04 + Aptabase main 镜像(2026-10-30)实测回显。
一、环境信息
- 操作系统:Ubuntu 22.04 LTS(x86_64)
- Aptabase:
ghcr.io/aptabase/aptabase:main(main 滚动镜像,2026-10-30 实测;API 无独立版本号,路径中v0为上报协议版本) - 实例地址:
http://192.168.1.200:8000(下文所有请求以它为基准,读者按自身实例替换) - 测试应用:
Demo Mobile App,appIdn85jSLY53PVjU3H7GBXZyU,appKeyA-SH-4878303621 - 部署背景:《Aptabase Docker Compose 部署指南》同一实例
二、前置条件
- 一个可用的自托管实例(部署见部署指南)与一个已注册管理员账号;
- 客户端工具:curl(本文全部实测用 curl 8.x)或任意 HTTP 客户端;
- 理解双轨认证(见第三章);
- 面板统计类接口需要「已出数」的应用——无数据时接口正常返回但数值为 0,属预期。
三、API 总览
3.1 接口域全景
| 域 | 路径前缀 | 认证 | 用途 |
|---|---|---|---|
| 认证 | /api/_auth/* | 无(登录本身)/ 会话 | 注册、登录、登出、账号信息 |
| 事件上报 | /api/v0/event、/api/v0/events | App-Key 请求头 | 客户端 SDK 上报(单条/批量) |
| 错误上报 | /api/v0/error | App-Key 请求头 | 客户端错误上报 |
| 功能开关 | /api/v0/feature-flags* | App-Key 请求头 | 客户端取值;管理端 /api/_flags* 走会话 |
| 应用管理 | /api/_apps* | 会话 | 创建/查询/更新/删除应用、分享与协作 |
| 面板统计 | /api/_stats/* | 会话 | 指标、时间序列、Top 榜、实时会话 |
| 数据导出 | /api/_export/* | 会话 | 用量与事件导出 |
| 协作请求 | /api/_app-requests、/api/_apps/{appId}/requests* | 会话 | 应用所有权/协作请求 |
| 计费 | /api/_billing* | 会话 | 云托管专用,自托管不可用 |
3.2 双轨认证机制(重要)
Aptabase 的接口认证分两轨,调用前先判断目标接口属于哪一轨:
App-Key请求头轨(客户端 SDK 域):事件/错误/功能开关上报只需在请求头携带App-Key: A-SH-xxxx(创建应用时生成),无用户身份,天然适合嵌入 App;- 会话 Cookie 轨(管理/面板域):需要先登录拿到
auth-sessionCookie。自托管版没有个人 API Token 机制,脚本化调用面板接口的方式是:走一次登录流程(见第四章)取得 Cookie 值,之后每个请求带Cookie: auth-session=<值>。
⚠️ 注意:
auth-sessionCookie 带Secure属性(部署指南常见问题 Q1),HTTP 直连场景下 curl 会拒绝在明文请求中回传该 Cookie,需在请求中显式携带Cookie:头或改走 HTTPS。生产环境统一 https 后无此问题。
四、认证域:注册、登录与首次调用
4.1 注册账号
curl -s -X POST http://192.168.1.200:8000/api/_auth/register \
-H 'Content-Type: application/json' \
-d '{"name":"admin","email":"admin@aptabase.local","password":"q1w2e3r4"}' \
-w "\n[%{http_code}]"
实测响应:
{}
[200]
成功响应体恒为空对象 {};注册失败(如邮箱已存在)返回 400 + ProblemDetails 错误体。
4.2 激活与登录(魔法链接模式)
自托管的登录是无密码魔法链接:signin 只提交邮箱,服务端向邮箱发送登录链接;未配置 SMTP 时链接写入应用日志(部署指南 4.5-4.6 节实测过取链接全过程)。
# 发起登录:只传 email
curl -s -X POST http://192.168.1.200:8000/api/_auth/signin \
-H 'Content-Type: application/json' \
-d '{"email":"admin@aptabase.local"}' -w "\n[%{http_code}]"
实测响应:
{}
[200]
从应用日志取 type 为 SignIn 的 continue 链接并 GET 访问,服务端 302 跳转首页并在响应头 Set-Cookie 中下发会话:
Set-Cookie: auth-session=CfDJ8ILAT-nFqHlBuaVofFU2h...; expires=Sat, 30 Oct 2027 02:42:39 GMT; max-age=31536000; path=/; secure; samesite=strict; httponly
注册激活(type=Register 的链接)与登录(type=SignIn)复用同一端点:GET /api/_auth/continue?token=<JWT>,token 有效期 15 分钟。
4.3 查看当前账号
curl -s http://192.168.1.200:8000/api/_auth/me \
-H "Cookie: auth-session=<登录取得的价值>" -w "\n[%{http_code}]"
实测响应:
{"id":"LFHJvK4ViazBQ0Aw9vCUGj","name":"admin","email":"admin@aptabase.local","avatarUrl":"https://aptabase.com/avatar/f9192f0b63fe0160a769ed571fd7be78?s=80&d=404","lockReason":null}
[200]
未携带有效会话时返回 401 + ProblemDetails(实测):
{"type":"https://tools.ietf.org/html/rfc9110#section-15.5.2","title":"Unauthorized","status":401,"traceId":"00-4dead3f71b09d90e4ea4cb9c1fa076a7-2f34483ab1577577-00"}
[401]
4.4 查询可用登录方式
curl -s http://192.168.1.200:8000/api/_auth/providers -w "\n[%{http_code}]"
实测响应(未配置 OAuth 时):
{"github":false,"google":false}
[200]
配置 GitHub/Google OAuth 环境变量后对应值变 true(配置方法见 《Aptabase 配置参数详解》5.5 节)。
五、事件上报域:/api/v0/event 与 /api/v0/events
5.1 事件体结构
单条事件请求体字段(实测归纳,systemProps 为必填嵌套对象):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
eventName | string | 是 | 事件名,建议蛇形/小驼峰,如 screen_view |
sessionId | string(UUID) | 是 | 会话 ID,客户端生成并复用(同一会话保持一致) |
props | object | 否 | 自定义事件属性(字符串键值) |
timestamp | string(ISO 8601) | 否 | 事件时间,UTC;缺省由服务端补 |
systemProps.sdkVersion | string | 是 | SDK 名称@版本,缺失返回 400 |
systemProps.osName / osVersion | string | 建议 | 操作系统及版本 |
systemProps.locale | string | 建议 | 语言区域 |
systemProps.appVersion | string | 建议 | 应用版本号(面板版本分布依据) |
5.2 单条上报 POST /api/v0/event
curl -s -X POST http://192.168.1.200:8000/api/v0/event \
-H 'App-Key: A-SH-4878303621' \
-H 'Content-Type: application/json' \
-d '{"eventName":"screen_view","sessionId":"3fa85f64-5717-4562-b3fc-2c963f66afa6","props":{"screen":"Home"},"timestamp":"2026-10-30T02:35:00Z","systemProps":{"osName":"Android","osVersion":"14","sdkVersion":"aptabase-js@1.2.0","locale":"zh-CN","appVersion":"1.0.0"}}' \
-w "\n[%{http_code}]"
实测响应:
{}
[200]
错误码实测:
- 缺
systemProps.sdkVersion→ 400(实测回显):
{"type":"https://tools.ietf.org/html/rfc9110#section-15.5.1","title":"One or more validation errors occurred.","status":400,"errors":{"SystemProps.SdkVersion":["The SdkVersion field is required."]},"traceId":"00-0c44c1e50f9cddacbb0bf16c77f8a254-04af4948a9c81b29-00"}
- App-Key 错误仍返回 200,错误藏在响应体(实测回显,排障时务必看体不看码):
{"error":"Application not found with given app key: A-SH-6809651776. Events are not being recorded."}
5.3 批量上报 POST /api/v0/events
请求体是事件对象数组(顶层 JSON 数组),不是 {"events":[...]} 包裹结构(实测:包裹结构返回 400,错误信息 The events field is required. 且提示目标类型为 EventBody[]):
curl -s -X POST http://192.168.1.200:8000/api/v0/events \
-H 'App-Key: A-SH-4878303621' \
-H 'Content-Type: application/json' \
-d '[{"eventName":"screen_view","sessionId":"b1b1b1b1-1111-4562-b3fc-2c963f66afa1","props":{"via":"batch"},"timestamp":"2026-10-30T04:00:00Z","systemProps":{"sdkVersion":"aptabase-js@1.2.0","osName":"Android","osVersion":"14","locale":"zh-CN","appVersion":"1.2.0"}}]' \
-w "\n[%{http_code}]"
实测响应:
{}
[200]
5.4 上报与可见性时序
事件先入应用内存缓冲,由后台任务批量刷入 ClickHouse,从上报到面板可见约 1 分钟(实测:连续上报后立即查询 metrics 为 0,等待约 45-60 秒后数据出现)。脚本化验证时需预留该延迟。
六、应用管理域:/api/_apps
以下接口均需会话 Cookie(下例中 Cookie: auth-session=<值> 简写为 $COOKIE)。
6.1 创建应用 POST /api/_apps
curl -s -X POST http://192.168.1.200:8000/api/_apps \
-H 'Content-Type: application/json' -H "Cookie: $COOKIE" \
-d '{"name":"Demo Mobile App"}' -w "\n[%{http_code}]"
实测响应:
{"id":"n85jSLY53PVjU3H7GBXZyU","name":"Demo Mobile App","appKey":"A-SH-4878303621","iconPath":"","hasEvents":false,"hasOwnership":false,"lockReason":null}
[200]
关键字段:id(后续面板查询用的 appId)、appKey(客户端上报凭据,A-SH 前缀代表自托管实例,实例级随机生成)、hasEvents(是否已产生事件)。
6.2 应用列表 GET /api/_apps
curl -s http://192.168.1.200:8000/api/_apps -H "Cookie: $COOKIE" -w "\n[%{http_code}]"
实测响应(上报数据后 hasEvents 变 true):
[{"id":"n85jSLY53PVjU3H7GBXZyU","name":"Demo Mobile App","appKey":"A-SH-4878303621","iconPath":"","hasEvents":true,"hasOwnership":true,"lockReason":null}]
[200]
6.3 应用详情 GET /api/_apps/{appId}
curl -s http://192.168.1.200:8000/api/_apps/n85jSLY53PVjU3H7GBXZyU -H "Cookie: $COOKIE" -w "\n[%{http_code}]"
实测响应:
{"id":"n85jSLY53PVjU3H7GBXZyU","name":"Demo Mobile App","appKey":"A-SH-4878303621","iconPath":"","hasEvents":true,"hasOwnership":true,"lockReason":null}
[200]
同路径还支持 PUT(改名/图标)与 DELETE(删除应用,数据不可恢复,本文不做破坏性实测)。
七、面板统计域:/api/_stats/*
统一参数:appId(应用 id,非 appKey)、periodStart / periodEnd(yyyy-MM-dd,闭区间)。以下全部实测。
7.1 核心指标 GET /api/_stats/metrics
curl -s "http://192.168.1.200:8000/api/_stats/metrics?appId=n85jSLY53PVjU3H7GBXZyU&periodStart=2026-10-01&periodEnd=2026-10-30" \
-H "Cookie: $COOKIE" -w "\n[%{http_code}]"
实测响应(current 为查询区间,previous 为等长前一时段,无数据时为 null):
{"current":{"dailyUsers":2,"sessions":9,"events":17,"durationSeconds":0},"previous":null}
[200]
7.2 时间序列 GET /api/_stats/periodic
curl -s "http://192.168.1.200:8000/api/_stats/periodic?appId=n85jSLY53PVjU3H7GBXZyU&periodStart=2026-10-01&periodEnd=2026-10-30&timezoneOffset=0" \
-H "Cookie: $COOKIE" -w "\n[%{http_code}]"
实测响应(按时间片聚合,事件集中在 02 时与 03-04 时两个片):
[{"period":"2026-10-30T02:00:00Z","users":2,"sessions":9,"events":17}]
[200]
timezoneOffset 单位为小时偏移(如东八区传 480,分钟制;实测传 0 为 UTC)。控制台曲线图数据源即此接口。
7.3 Top 榜系列
事件 Top 榜:
curl -s "http://192.168.1.200:8000/api/_stats/top-events?appId=n85jSLY53PVjU3H7GBXZyU&periodStart=2026-10-01&periodEnd=2026-10-30" \
-H "Cookie: $COOKIE" -w "\n[%{http_code}]"
实测响应:
[{"name":"screen_view","value":9},{"name":"button_click","value":8}]
[200]
应用版本分布:
[{"name":"1.2.0","value":8},{"name":"1.0.0","value":1}]
[200]
操作系统分布(实测响应):[{"name":"Android","value":5},{"name":"iOS","value":4}]。
地区与设备分布(实测响应为空名 ""——SDK 上报未携带地理位置/设备信息时聚合为空值桶):
[{"name":"","value":9}]
说明:top 系列共享同一参数与返回结构(
name/value数组),同一族还有top-osversions、top-regions、top-appbuildnumbers、top-props,不再重复回显。空值桶不是故障——是「上报数据未包含该维度」的真实映射。
八、其他域接口概览
以下接口经服务端路由实证存在(自托管 main 镜像,2026-10-30),本文未做逐条破坏性实测,只列清单供排查与集成参考:
- 错误上报:
POST /api/v0/error(客户端上报崩溃/异常)、GET /api/v0/apps/{appId}/errors及/errors/types、/errors/{errorId}(错误聚合查询); - 功能开关:
GET /api/v0/feature-flags/{featureFlagKey}(客户端取值)、POST/PUT/DELETE /api/_flags*(管理端,会话认证); - 数据导出:
GET /api/_export/usage、GET /api/_export/download; - 实时会话:
GET /api/_stats/live-sessions、live-geo、live-session-details、historical-sessions; - 协作:
POST /api/_apps/{appId}/shares/{email}(分享)、GET /api/_apps/{appId}/requests(所有权请求,accept/reject 子路径); - 账号:
POST /api/_auth/signout、POST /api/_auth/account/delete。
九、通用约定
- Content-Type:全部为
application/json;响应体 JSON,成功写操作通常为空对象{}; - 错误格式:校验/鉴权错误统一返回 ASP.NET ProblemDetails 结构(
type/title/status/errors/traceId),errors内为字段级错误明细; - 时间参数:面板域一律
periodStart/periodEnd(yyyy-MM-dd);事件体timestamp用 ISO 8601 UTC; - 两个 ID:面板与管理接口用
appId(如n85jSLY53PVjU3H7GBXZyU),上报接口用appKey(如A-SH-4878303621),两者不可混用; - 幂等与限流:接口层无显式限流头;重复上报同一 sessionId+eventName 会被会话归并逻辑处理,但无去重保证,客户端重试需自行权衡;
- 数据可见性:上报域 200 ≠ 已入库,统一以约 1 分钟后台刷新后的面板域接口为准。
十、常见问题
Q1:上报一直 200 但面板始终为 0?
先看上报响应体是否为 {"error":"Application not found with given app key: ..."}(App-Key 错误时状态码仍是 200);再确认等待了 1 分钟以上;最后检查事件 timestamp 是否落在查询的 periodStart/periodEnd 区间内(传未来时间在默认区间看不到)。
Q2:批量接口报 "The events field is required."?
/api/v0/events 的请求体是顶层 JSON 数组 [ {...}, {...} ],不要包成 {"events":[...]}。
Q3:脚本调用面板接口 401?
自托管无 API Token,必须携带浏览器登录取得的 auth-session Cookie;同时注意 Cookie 的 Secure 属性在 http:// 下不能自动回传,脚本中显式设置 Cookie: 头。
Q4:me 接口返回的 avatarUrl 指向 aptabase.com? 头像由服务端按邮箱哈希指向公共头像服务生成,属正常行为;内网隔离环境头像加载失败不影响功能。
十一、参考链接
- 主仓库(API 服务端源码):https://github.com/aptabase/aptabase
- 自建 SDK 指南(上报协议来源):https://github.com/aptabase/aptabase/wiki/How-to-build-your-own-SDK
- 部署与实例初始化:《Aptabase Docker Compose 部署指南》
- 认证/SMTP/OAuth 相关配置:《Aptabase 配置参数详解》
- 项目定位与同类选型:《Aptabase 介绍与选型指南》