Skip to content

首页 API 接口参考 ​

首页本屏 + 全部跳转详情页 —— 17 个端点 / 4 个域 契约基准:后端源码(QM-ServerV2)· 前端基线 qm-frontend-api @ d9a357c 本文只写接口,不写背景与结论

通用约定 ​

请求 ​

项值
方法POST —— 17 个端点全部是 POST
路径/api/v1/<域>(域:stats / device / sport / health-archive)
Content-Typeapplication/json
AuthorizationBearer <access_token> —— 必填,缺失即 401
X-EnvDev 或 Prd —— 必填,且与 token 签发时一致(不一致直接失效)

请求体 ​

字段类型必填说明
actionstring✔action 名(各端点见下文)
payloadobject✖入参;无入参的 action 可省略该键

⚠️ 入参一律在 payload 内,不是 body 顶层。

周期模式(period 契约 · 2026-09-28 上线) ​

全部健康详情 action 支持可选的 period 模式(对 DETAIL_API_PARAMS.md 目标契约的落地)。

入参(与 date 并存;三字段成对出现):

字段类型必填说明
periodstring✖day | week | month | year(各 action 支持面见下表)
startDatestring✖区间起(含),YYYY-MM-DD 真实公历
endDatestring✖区间止(含)

规则:

  • 不传 period → legacy 模式:响应含全部周期块(现状,逐字兼容)
  • 传 period → 必须成对传 startDate/endDate(缺一 → 40403001)。区间与 period 一致性校验:week 必须周一至周日(连续 7 天);month 必须 1 日至月末(实际天数);year 必须 01-01 至 12-31(闰年自然支持);day 起止同日
  • date 缺省取 startDate;给了必须落在 [startDate, endDate] 内(否则 40403001)
  • 出参裁剪:data 只含所请求周期的块 + 公共键 period/date/startDate/endDate + 周期无关元数据(vendor 等);其余周期键整体省略(不用 null/{} 占位)
  • 周期专属块仅在对应请求出现:heartRateDetail.todaySeries / oxygenDetail.overview·card / stressDetail.card 仅 day;sleepDetail 的 dayMetrics·daySegments·bedWake·score·stages 仅 day、weekRanges 仅 week、monthRanges 仅 month

各 action 支持面(不支持 → 40403001 明确报错,不静默降级):

actiondayweekmonthyear
stepsDetail / caloriesDetail / strengthDetail✔✔✔✖(无 year 块)
sleepDetail✔✔✔✖
activitySummary✔✔✔(含 monthDays)✖
heartRateDetail / stressDetail / weightDetail✔✔✔✔
oxygenDetail✔✔✔✖

示例(周视图):

json
{
  "action": "stepsDetail",
  "payload": {
    "period": "week",
    "date": "2026-09-10",
    "startDate": "2026-09-07",
    "endDate": "2026-09-13"
  }
}

→ data 仅含 week 块 + period/date/startDate/endDate(+ vendor 条件出现)。

响应信封 ​

json
{ "code": "0", "msg": "ok", "data": {} }
字段类型说明
codestring"0" = 成功。非 "0" 时 HTTP 仍可能是 200 —— 请判 code,不要只判 status
msgstring"ok" 或错误描述
dataobject各端点返回体

记号 ​

记号含义
类型后 | null该字段可能为 null
恒 null后端无数据源,永远返回 null(前端须按无数据渲染)
条件出现仅在特定条件下才存在的键(不出现 ≠ 为 null)

端点一览 ​

#域action页面入参
1statsgetTodayOverview首页 · 热量 / 连续天数卡—
2devicemyTodayHealth首页 · 健康卡—
3deviceoxygenDetail首页 · 血氧卡 → 血氧详情页date?
4devicestressDetail首页 · 压力卡 → 压力详情页date?
5deviceweightDetail首页 · 体重卡 → 体重详情页date?
6devicestrengthDetail首页 · 力量卡 → 力量详情页date?
7sportmyRunRecords首页 · 运动卡 → 运动数据页period? limit?
8devicesleepDetail睡眠详情页date?
9deviceheartRateDetail心率详情页date?
10deviceactivitySummary健康汇总页date? month?
11devicecaloriesDetail卡路里详情页date?
12devicestepsDetail步数详情页date?
13devicerecordDates日期选择页(6 处入口)days?
14sportrunSessionDetail运动详情页sessionId
15sportaddWeightRecord添加体重页date weight …
16sportreportRunCoordinate运动数据页 · 轨迹上报sessionId latitude …
17health-archivearchive健康档案页—

首页本屏并发发出 #1–#7 共 7 个;其余在对应详情页触发。


一、首页本屏(7 个) ​

1. getTodayOverview ​

stats · 首页热量 / 连续天数卡 · 无入参

入参 payload

字段类型必填说明
—无入参,payload 可省

出参 data

字段类型说明
datestringCN 今日 YYYY-MM-DD
calorieobject热量块 ↓
calorie.budgetKcalnumber | null热量预算(int)。画像不全 = null(不编数)
calorie.intakeKcalnumber已摄入(float)。无记录 = 0
calorie.burnKcalnumber已消耗 = 跑步 + 力量(float)。无记录 = 0
calorie.remainingKcalnumber | null剩余额度 = budget + burn − intake,向零截断(int)。画像不全 = null
calorie.profileCompletebooleanfalse = 画像缺失 → 上两项为 null
checkinobject打卡块 ↓
checkin.countnumber当日打卡数(int)
checkin.distanceKmnumber当日打卡总距离(float)。无打卡 = 0

⚠️ 没有 basis 字段 —— basis 属于 stats.calorieBalance action(另一个端点)。 ⚠️ calorie 是嵌套的:读 res.data.calorie.budgetKcal,不是 res.data.budgetKcal。 ⚠️ budgetKcal / remainingKcal 为 null 时请渲染 --,不要兜默认值。

bash
curl -s "$BASE_URL/api/v1/stats" -H 'Content-Type: application/json' \
  -H "X-Env: $ENV" -H "Authorization: Bearer $ACCESS" \
  -d '{"action":"getTodayOverview","payload":{}}'

2. myTodayHealth ​

device · 首页健康卡 · 无入参 · 块状结构(非扁平字段)

入参 payload

字段类型必填说明
—无入参

出参 data

字段类型说明
datestringCN 今日 YYYY-MM-DD
steps{value, date} | null步数块(value int / date string)。无数据 = null
todayActivity{totalCalories, totalDistanceKm} | null当日活动块(number / number,距离保留 2 位)。无当日行 = null
hr{value, date} | null心率块
spo2{value, date} | null血氧块(v2.0.64 解禁:当日有 SPO2 读数则给)。无读数 = null
stress{value, date} | null压力块(v2.0.64 新增)。无读数 = null
weight{value, date} | null体重块(v2.0.64 新增,最新一条体成分,date 为 CN 日)。无数据 = null
sleepobject | null睡眠块 ↓
sleep.durationHoursnumber总时长(小时)
sleep.deepHoursnumber | null深睡(小时,1 位小数)。分段为空 = null
sleep.lightHoursnumber | null浅睡(小时,1 位小数)
sleep.remHoursnumber | nullREM(小时,1 位小数)
sleep.score恒 null睡眠评分 —— V2 sync 无该来源
sleep.datestring睡眠所属日
sourcesobject数据来源映射 {steps?, hr?, spo2?, stress?, sleep?, weight?} —— 各键值 = 厂商 id。无数据时为 {},键按有无数据出现

⚠️ 顶层只有这 9 个键:date / steps / todayActivity / hr / spo2 / stress / weight / sleep / sources(v2.0.64 起 stress/weight 加入)。 顶层没有 distance —— 距离在 todayActivity.totalDistanceKm。 steps / hr 是 {value, date} 对象,不是数字。

⭐ 新用户初始化语义(v2.0.64):7 天窗内无任何设备行/读数的新用户,累积量(steps / todayActivity)返回 0(今天确实没走没记 —— 真实状态);测量量(hr / spo2 / stress / sleep)保持 null(心率 0 荒谬)。老用户缺当日行 → 同样 null(--)。


3. oxygenDetail ​

device · 血氧 · 入参同 端点 8 的通用形态

入参 payload

字段类型必填默认说明
datestring✖CN 今日锚点日 YYYY-MM-DD。格式非法 → 400

出参 data

字段类型说明
datestring锚点日
summaryMapobject按窗口映射:键 day / week / month / year,值 {date, average}(average int)
pointSetsobject按窗口的散点序列
overview{max, min, average} | null当日概览(均为 int)。当日无值 = null
cardobject | null首页卡视图 {oxygen, measureTime, series24}。measureTime / series24 恒 null(无逐样本源)
pointSetsEchartsobject⭐ echarts 5.6 dataset-ready(v2.0.63 新增,平行字段)—— {dimensions, source, labels, dates},见共享结构 · echarts 数据包装
vendorstring条件出现 —— 仅在有数据来源时出现在顶层

4. stressDetail ​

device · 压力 · 入参同 端点 8

入参 payload

字段类型必填默认说明
datestring✖CN 今日锚点日 YYYY-MM-DD

出参 data

字段类型说明
datestring锚点日
summaryMapobject按窗口映射:{date, average}
distributionMapobject按窗口的等级分布(放松 / 中等 / 偏高 三带)
pointSetsobject按窗口的散点序列
cardobject | null首页卡 {stress, level, date, measureTime, series24}。level ∈ 放松 / 中等 / 偏高;series24 为 24 项逐时序列(v2.0.64 起:raw.samples 逐时组装,无采样 → null);measureTime 恒 null
pointSetsEchartsobject⭐ echarts 5.6 dataset-ready(v2.0.63 新增,平行字段)—— {dimensions, source, labels, dates},见共享结构 · echarts 数据包装
vendorstring条件出现

等级带阈值:≤33 放松 · ≤66 中等 · else 偏高。


5. weightDetail ​

device · 体重 · 入参同 端点 8

入参 payload

字段类型必填默认说明
datestring✖CN 今日锚点日 YYYY-MM-DD

出参 data

字段类型说明
datestring锚点日
currentobject当前值块 ↓
current.weightstring | null体重文本(带单位)
current.weightValuenumber | null体重数值(2 位小数)
current.datestring | null测量日
current.bminumber | nullBMI(1 位小数)
current.statusstring | nullBMI 状态文案
current.initialWeightstring | null初始体重文本
current.targetWeight恒 null目标体重 —— 目标域未落表
current.lostWeightstring | null已减重文本
current.progressPercent恒 null无目标 → 无进度
current.progressText恒 null同上
caloriesobject{intake, suggested, burned, remaining} —— 四项恒 null(热量属 stats 域)
dataMapobject按窗口的体重序列(2 位小数,含统计量)
fatMapobject按窗口的体脂序列(1 位小数)
muscleMapobject按窗口的肌肉量序列(1 位小数)
vendorstring条件出现

6. strengthDetail ​

device · 中高强度 · 入参同 端点 8

入参 payload

字段类型必填默认说明
datestring✖CN 今日锚点日 YYYY-MM-DD

出参 data —— 三个同构活动块(见 共享结构 · 活动块)

字段类型说明
dayobject日块(锚点日)
weekobject周块
monthobject月块
vendorstring条件出现

块的 strength 键 = 该窗口合计分钟数。


7. myRunRecords ​

sport · 首页运动卡 / 运动数据页

入参 payload

字段类型必填默认说明
periodstring✖all枚举:week / month / year / all
limitnumber✖200记录条数上限,范围 1–500

出参 data

字段类型说明
periodstring回显入参
sincestring | null统计起点(all 时为 null)
summaryobject全量累计摘要,见 共享结构 · 累计摘要
periodSummaryobject本周期累计摘要(同结构)
recordsarray记录行数组,见 共享结构 · 运动记录行
groupsarray按日期分组的展示结构

二、详情页(10 个) ​

8. sleepDetail ​

device · 睡眠详情页 —— 本端点是与 #3/#4/#5/#6/#9/#11/#12 同款的「通用形态」

入参 payload

字段类型必填默认说明
datestring✖CN 今日锚点日 YYYY-MM-DD,正则 ^\d{4}-\d{2}-\d{2}$。非法 → 40403001 400

出参 data

字段类型说明
datestring锚点日
summariesobject按窗口的睡眠摘要
dayMetricsobject按窗口的日指标
scorenumber | null睡眠评分
stagesobject | null分期构成
bedWakeobject | null入睡 / 起床时刻
daySegmentsobject日内分段
weekRangesobject周区间
monthRangesobject月区间
periodMetricsobject各周期指标
rangesEchartsobject⭐ echarts 5.6 dataset-ready(v2.0.63 新增)—— {week: 包装, month: 包装},见共享结构 · echarts 数据包装
vendorstring条件出现

9. heartRateDetail ​

device · 心率详情页

入参 payload

字段类型必填默认描述
datestring✖CN 今天要查哪一天的心率(历史日也可传),格式 YYYY-MM-DD,非法 → 40403001 400

出参 data

字段类型描述
datestring锚点日(= 入参 date 或今天)
summaryMapobject按档位摘要:键 day/week/month/year,值 {label, value, date};hour 档恒 null(无逐时源)
metricsMapobject当日指标卡:范围 / 静息心率 / 步行平均心率(恒 null —— 厂商无源)
rangeSetsobject按档位范围序列;hour 档恒 null
restingSourcestring静息心率取值来源:'REST_HR'(专列)或 'HR'(回退)
todaySeriesarray | null⭐ 当日 24 小时逐时心率(详见〔todaySeries 详解〕)
rangeSetsEchartsobject⭐ echarts 5.6 dataset-ready 平行字段(dimensions/source/labels/dates)
vendorstring条件出现:数据来源厂商(simulated = 示例数据)

〔todaySeries 详解〕—— 心率详情页日档折线图的数据源 ​

  • 形态:长度 24 的数组,下标 = CN 小时 0–23,值 = 该小时心率(float);该小时无采样 → null
  • 数据来源:当日 health_metric 行的 raw.samples(honor hourly job 每小时拉的采样集明细,样本含 startTime + dynamicHeartRate)
  • 何时有值:绑定 honor 设备 且 hourly job 运行 且 当日有采样 —— 三者缺一即 null
  • 渲染建议:折线/柱状图;null 处断点(不连线、不补 0 —— 与「诚实空态」口径一致)

实测样例响应(锚点 2026-09-20 · 生产真数据 · 节选):

json
{
  "code": "0",
  "data": {
    "date": "2026-09-20",
    "summaryMap": {
      "day":  {"label": "范围", "value": "69", "date": "2026年9月20日"},
      "week": {"label": "范围", "value": "63-70", "date": "2026年9月14日–20日"}
    },
    "rangeSets": {
      "week": [[0, 63, 63], [1, 65, 65], [2, 65, 65], [3, 67, 67], [4, 66, 66], [5, 65, 65], [6, 69, 69]]
    },
    "rangeSetsEcharts": {
      "week": {
        "dimensions": [{"name":"index","type":"int"},{"name":"low","type":"float"},{"name":"high","type":"float"}],
        "source": [[0, 63, 63], [1, 65, 65], [2, 65, 65], [3, 67, 67], [4, 66, 66], [5, 65, 65], [6, 69, 69]],
        "labels": ["一", "二", "三", "四", "五", "六", "日"],
        "dates":  ["2026-09-14", "2026-09-15", "2026-09-16", "2026-09-17", "2026-09-18", "2026-09-19", "2026-09-20"]
      }
    },
    "restingSource": "REST_HR",
    "todaySeries": null
  }
}

更多说明:API 空值字段与样例说明(恒 null 全量清单 + 逐时序列抢救路径与解禁记录)。


10. activitySummary ​

device · 健康汇总页 · 条件键最多

入参 payload

字段类型必填默认说明
datestring✖CN 今日锚点日 ^\d{4}-\d{2}-\d{2}$
monthstring✖—YYYY-MM。传了才返回 month / monthDays;非法月份 → 40403001 400

出参 data

字段类型说明
datestring锚点日
anchorstring同 date
goalsobject目标值 {steps: 8000, calories: 400, strength: 30}
dayobject单日活动视图,见 共享结构 · 单日活动视图
weekarray7 天数组:[{weekday, ...精简视图}]
monthstring条件出现 —— 仅传 payload.month 时。回显 YYYY-MM
monthDaysarray条件出现 —— 仅传 payload.month 时。[{day, ...精简视图}]
vendorstring条件出现

11. caloriesDetail ​

device · 卡路里详情页 · 入参同 端点 8

出参 data —— 三个同构活动块(见 共享结构 · 活动块)

字段类型说明
day / week / monthobject块的 calories 键 = 该窗口合计千卡
vendorstring条件出现

12. stepsDetail ​

device · 步数详情页 · 入参同 端点 8

出参 data —— 三个同构活动块

字段类型说明
day / week / monthobject块的 steps 键 = 该窗口合计步数;含距离指标(块内 metrics 多两项)
vendorstring条件出现

13. recordDates ​

device · 日期选择页(6 处入口共用)

入参 payload

字段类型必填默认说明
daysnumber✖180回溯天数,范围 1–366

出参 data

字段类型说明
daysnumber回显入参
datesarray有记录的日期数组(YYYY-MM-DD)

14. runSessionDetail ​

sport · 运动详情页

入参 payload

字段类型必填说明
sessionIdstring✔会话 id 或打卡 id —— 两者同字段,长度 1–64

出参 data

字段类型说明
kindstring'session'(跑步会话)或 'checkin'(打卡)
idstring会话 / 打卡 id
summaryobject摘要,见 共享结构 · 会话摘要
routePointsarray轨迹点
paceSeriesarray配速序列
paceLapsarray配速分段
heartZonesarray | null心率区间分布
heartSeriesarray心率序列
cadenceSeriesarray步频序列
strideSeriesarray步幅序列
elevationSeriesarray海拔序列

15. addWeightRecord ​

sport · 添加体重页 · 写操作

入参 payload

字段类型必填默认说明
datestring✔—YYYY-MM-DD(东八区本地)
timestring✖00:00HH:mm(东八区本地)
weightnumber✔—体重
bodyFatnumber✖—体脂率

出参 data

字段类型说明
okboolean是否成功
idstring新记录 id
datestring回显
timestring回显(缺省补 00:00)
weightnumber回显
bodyFatnumber | null回显

16. reportRunCoordinate ​

sport · 运动数据页 · 轨迹上报(约 10s / 点) · 写操作

入参 payload

字段类型必填单位 / 说明
sessionIdstring✔长度 1–64
activityTypestring✔活动类型枚举
latitudenumber✔纬度
longitudenumber✔经度
locationTimestampnumber✔epoch 毫秒(数值型,兼容 JS 浮点毫秒)
accuracynumber✖定位精度
speednumber✖m·s⁻¹
distancenumber✖累计米
durationnumber✖累计毫秒
reportTimestampnumber✖epoch 毫秒(存证)

⚠️ 单位与前端实参一致:距离米 / 时长毫秒 / 速度 m·s⁻¹ / 时间戳 epoch 毫秒。

出参 data

字段类型说明
okboolean是否接收成功
receivedAtstring服务端接收时刻

17. archive ​

health-archive · 健康档案页 · 无入参

出参 data —— 7 个组件

字段类型说明
basicInfoobject{age, gender, height, weight, bmi}
healthIncidentobject{symptom, injuries, updatedAt} —— updatedAt 为 ISO 串或 null
physiologicalobject{hrv, sleepHours, heartRateRecovery, activeMetabolism};heartRateRecovery 恒 null(厂商云无该指标)
cardiopulmonaryobject{maxHeartRate, restingHeartRate, lactateThresholdHeartRate, vo2max}
heartRateZonesobject{method, methodLabel, thresholds, zones, derived} ↓
heartRateZones.thresholdsnumber[] | null恰 4 个,60–240,严格递增
heartRateZones.zones[{name, value, color}] | null可为 null —— 直接用 .length 会抛 TypeError
runningAbilityobject{vdot, records};records = [{key, label, value}],无成绩时 value 为 null
compatibilityRangesobject{zones};zones = [{name, value, desc, color}],可为 null(无打卡成绩时推导不出)
dataSourcestring条件出现 —— 仅含模板示例数据时
defaultDimsarray条件出现 —— 同上,哪几项来自模板

写路径(saveHealthIncident / saveHeartRateZones)不在本文范围 —— 健康档案页当前不调用。


共享结构 ​

共享结构·echarts 数据包装 ​

rangeSetsEcharts / pointSetsEcharts / rangesEcharts(v2.0.63 起)—— 后端按 echarts 5.6 dataset 规范产出的图表数据,前端可零转换消费:

js
chartOption = {
  dataset: { dimensions: ec.dimensions, source: ec.source },
  xAxis: { type: 'category', data: ec.labels },   // 全桶标签(含空桶)—— 后端权威给出
  series: [{ type: 'custom', encode: { x: 'index', y: ['low', 'high'] }, renderItem }],
}
字段类型说明
dimensionsarray{name, type},type ∈ int / float(TypedArray 性能优化)
sourcearray与旧 points 同源同值([[index, low, high], …],稀疏)
labelsstring[]全桶标签(含无数据桶)—— 周 '一'…'日' · 月 '1'…'31' · 年 '1'…'12' · 日 日号
datesstring[]全桶真实日期(ISO)—— tooltip / 校验用

旧字段(rangeSets / pointSets / weekRanges / monthRanges)原样保留,本字段为平行新增。

共享结构·活动块 ​

stepsDetail / caloriesDetail / strengthDetail 三者的 day / week / month 同构:

字段类型说明
datestring窗口锚点日
subtitlestring | null日块恒 null(无逐样本源);周 / 月块 = date
steps | calories | strengthnumber | null键名随端点变。该窗口合计(int)
overviewTitlestring概览标题文案
metricsarray[{label, value, unit?}] —— value 为 string,无数据为 null
labelsarray横轴标签。日块 = 24 个 HH:00;周块 = 周一…周日;月块 = 日号
valuesarray | null纵轴值。日块恒 null(无逐小时源)

日块的 metrics 含:今日步数/消耗/中高强度 +(stepsDetail 另有)今日距离。 周 / 月块含:总X / 日均X +(stepsDetail 另有)总距离 / 日均距离。

共享结构·单日活动视图 ​

activitySummary.day:

字段类型说明
datestring日期
steps / calories / strengthnumber | null当日三值(int)
distancenumber | null公里(2 位小数)
stepsPercent / caloriesPercent / strengthPercentnumber | null相对目标百分比
stepData / calorieData / strengthData恒 null24 点逐小时序列 —— 无源

activitySummary.week[] / monthDays[] 用精简视图 = 上述 7 项(去掉三个 *Data)+ weekday(仅 week)/ day(仅 monthDays)。

共享结构·运动记录行 ​

myRunRecords.records[] —— kind 区分两种来源,字段名相同:

字段类型kind='session'kind='checkin'
idstring会话 id打卡 id
kindstring'session''checkin'
activityTypestring实际类型恒 running
labelstring类型中文名恒「跑步」
datestring东八区历日CN 日期串
timestringHH:mmHH:mm
startedAtstring | nullISO恒 null
distanceKmnumber公里公里(2 位小数)
durationSecnumber秒秒(缺省 0)
pacestring | null平均配速平均配速(缺则计算)
heartRatenumber | null平均心率平均心率
caloriesnumber | null热量恒 null(打卡契约无热量字段,不编造)
detailstring展示文案展示文案(含步频时追加)

共享结构·累计摘要 ​

myRunRecords.summary / periodSummary:

字段类型说明
countnumber记录数
distanceKmnumber总距离(2 位小数)
durationSecnumber总时长(秒)
durationMinnumber总时长(分钟)
caloriesnumber | null总热量
avgHeartRatenumber | null平均心率
avgPacestring | null平均配速

共享结构·会话摘要 ​

runSessionDetail.summary:

字段类型说明
sessionIdstring会话 id
activityTypestring活动类型
labelstring类型中文名
statusstring会话状态
startedAtstring开始时刻(ISO)
endedAtstring | null结束时刻
distanceKmnumber | null距离
durationSecnumber | null时长(秒)
avgPacestring | null平均配速
caloriesnumber | null热量
avgHrnumber | null平均心率
stepsnumber | null步数

错误码 ​

域段常用码
device40403xxx40403001 参数非法 → 400 · 40403002 未登录 → 401
stats40422xxx40422001 参数非法 → 400 · 40422002 未登录 → 401
sport40418xxx40418001 参数非法 → 400 · 40418002 未登录 → 401
health-archive40427xxx40427001 参数非法 → 400 · 40427002 未登录 → 401

⚠️ 业务码优先:失败时 HTTP 状态与 code 都要看。多数参数 / 鉴权错误返对应的 4xx, 但部分业务失败(如样本不足 40422005)返 HTTP 200 + 非 0 code。


字段与类型均取自后端源码(Pydantic 入参模型 + 用例返回构造)。发现与实现不符处,请附原始输出提出复核。