# POST /api/v1/analytics/events — 批量上报埋点事件 > 所属:Analytics 组(前缀 `/api/v1/analytics`) | 鉴权:无(不强制登录,未登录态也要采集行为) | [← 返回 API 索引](../README.md) 批量接收新手引导(及后续)埋点,append 落 `analytics_event` 表。`user_id` 由客户端在 body 可选带上,不靠 Bearer。服务端补 `client_ip`(X-Forwarded-For)与 `server_at`(接收时间)。 ## 入参 | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `device_id` | string | ✅(≤64) | 设备 ID | | `user_id` | int \| null | ❌ | 登录用户 ID(未登录可空) | | `sent_at` | int \| null | ❌ | 批次发送时间(epoch ms) | | `oem` | string \| null | ❌ | 厂商(如 `Xiaomi`) | | `os` | string \| null | ❌ | 操作系统(如 `Android 14`) | | `model` | string \| null | ❌ | 机型(如 `24115RA8EC`) | | `app_ver` | string \| null | ❌ | App 版本 | | `channel` | string \| null | ❌ | 渠道 | | `events` | list[object] | ✅(1-200 条) | 事件数组 | | `events[].event` | string | ✅(≤64) | 事件名(如 `onboarding_start`) | | `events[].client_ts` | int | ✅ | 端事件发生时间(epoch ms) | | `events[].session_id` | string \| null | ❌ | 会话 ID | | `events[].page` | string \| null | ❌ | 页面标识 | | `events[].network` | string \| null | ❌ | 网络类型(如 `wifi`) | | `events[].props` | dict | ❌ | 事件属性(key-value) | Mock 入参: ```json { "device_id": "android_abc123def456", "user_id": 42, "sent_at": 1719993700000, "oem": "Xiaomi", "os": "Android 14", "model": "24115RA8EC", "app_ver": "0.1.5", "channel": "official", "events": [ { "event": "onboarding_start", "client_ts": 1719993600000, "session_id": "sess_a1b2c3", "page": "onboarding", "network": "wifi", "props": {"step": "1", "source": "fresh_install"} }, { "event": "onboarding_step_complete", "client_ts": 1719993615000, "session_id": "sess_a1b2c3", "page": "onboarding", "network": "wifi", "props": {"step": "1", "duration_ms": "15000"} } ] } ``` ## 出参 响应 `200`:`AnalyticsIngestOut` | 字段 | 类型 | 说明 | |---|---|---| | `ok` | bool | 固定 `true` | | `received` | int | 成功写入的条数 | Mock 出参: ```json { "ok": true, "received": 2 } ``` ## 错误码 - `422` `events` 为空或超过 200 条 / 字段类型不符 ## 说明 - `user_id` 不靠 JWT:未登录态也要采集行为(新手引导可能在登录前) - 每批最多 200 条,建议客户端攒到一定量再批量上报 - `client_ts` 是端侧时间(客户端时钟),`server_at` 由服务端补(可靠时间轴)