Aptabase API 使用详解

Aptabase API 使用详解:认证/事件上报(单条+批量)/应用管理/面板统计四大域接口逐条实测(含真实请求与响应回显)、App-Key 与会话认证双轨制、错误码与通用约定,基于 main 镜像(2026-10-30)实测。

AptabaseAptabase产品分析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,appId n85jSLY53PVjU3H7GBXZyU,appKey A-SH-4878303621
  • 部署背景:《Aptabase Docker Compose 部署指南》同一实例

二、前置条件

  1. 一个可用的自托管实例(部署见部署指南)与一个已注册管理员账号;
  2. 客户端工具:curl(本文全部实测用 curl 8.x)或任意 HTTP 客户端;
  3. 理解双轨认证(见第三章);
  4. 面板统计类接口需要「已出数」的应用——无数据时接口正常返回但数值为 0,属预期。

三、API 总览

3.1 接口域全景

域路径前缀认证用途
认证/api/_auth/*无(登录本身)/ 会话注册、登录、登出、账号信息
事件上报/api/v0/event、/api/v0/eventsApp-Key 请求头客户端 SDK 上报(单条/批量)
错误上报/api/v0/errorApp-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-session Cookie。自托管版没有个人 API Token 机制,脚本化调用面板接口的方式是:走一次登录流程(见第四章)取得 Cookie 值,之后每个请求带 Cookie: auth-session=<值>。

⚠️ 注意:auth-session Cookie 带 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 为必填嵌套对象):

字段类型必填说明
eventNamestring是事件名,建议蛇形/小驼峰,如 screen_view
sessionIdstring(UUID)是会话 ID,客户端生成并复用(同一会话保持一致)
propsobject否自定义事件属性(字符串键值)
timestampstring(ISO 8601)否事件时间,UTC;缺省由服务端补
systemProps.sdkVersionstring是SDK 名称@版本,缺失返回 400
systemProps.osName / osVersionstring建议操作系统及版本
systemProps.localestring建议语言区域
systemProps.appVersionstring建议应用版本号(面板版本分布依据)

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。

九、通用约定

  1. Content-Type:全部为 application/json;响应体 JSON,成功写操作通常为空对象 {};
  2. 错误格式:校验/鉴权错误统一返回 ASP.NET ProblemDetails 结构(type/title/status/errors/traceId),errors 内为字段级错误明细;
  3. 时间参数:面板域一律 periodStart/periodEnd(yyyy-MM-dd);事件体 timestamp 用 ISO 8601 UTC;
  4. 两个 ID:面板与管理接口用 appId(如 n85jSLY53PVjU3H7GBXZyU),上报接口用 appKey(如 A-SH-4878303621),两者不可混用;
  5. 幂等与限流:接口层无显式限流头;重复上报同一 sessionId+eventName 会被会话归并逻辑处理,但无去重保证,客户端重试需自行权衡;
  6. 数据可见性:上报域 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? 头像由服务端按邮箱哈希指向公共头像服务生成,属正常行为;内网隔离环境头像加载失败不影响功能。

十一、参考链接

  1. 主仓库(API 服务端源码):https://github.com/aptabase/aptabase
  2. 自建 SDK 指南(上报协议来源):https://github.com/aptabase/aptabase/wiki/How-to-build-your-own-SDK
  3. 部署与实例初始化:《Aptabase Docker Compose 部署指南》
  4. 认证/SMTP/OAuth 相关配置:《Aptabase 配置参数详解》
  5. 项目定位与同类选型:《Aptabase 介绍与选型指南》