477 lines
19 KiB
Markdown
477 lines
19 KiB
Markdown
# 设备注册与绑定接口简版
|
||
|
||
按当前 SaaS 代码整理,适用协议 `ONBOARDING-1.2-SAAS`。
|
||
|
||
正常流程:**后台登记并放行 → 设备联网认证 → 打开手机绑定页 → 用户登录并提交绑定 → 设备按键确认 → 保存绑定结果 → 激活语音服务。**
|
||
|
||
`register` 成功表示设备身份认证通过;`binding_state=BOUND` 才表示绑定成功;`activation_state=READY` 表示语音服务已就绪。
|
||
|
||
## 阅读约定
|
||
|
||
- 每个接口只列用途、输入和输出。输入示例为请求 JSON;输出示例为响应 `data` 的主要字段,已省略部分状态和时间字段。
|
||
- `<…>` 都是占位值,须替换为实际返回值或设备生成值;UUID、密钥、签名不能照抄占位值。版本号也必须使用最新返回值。
|
||
- 路径前加实际 SaaS 域名,例如 `https://saas.example`。请求使用 `Content-Type: application/json`;下面 POST 请求统一携带 `X-Request-ID`(UUID v4)。
|
||
- 设备接口除校时外,需要设备签名请求头;手机接口使用浏览器 Cookie,兑换入口后的 POST 还需 `X-CSRF-Token`,并按同源请求调用;运维接口需要运维登录凭证和 `X-Tenant-ID`。具体签名见[设备注册接口说明](设备注册接口说明.md)。
|
||
- 这是代码中的接口清单,实际可用性取决于部署开关;短信登录需要已配置并开启短信服务。
|
||
|
||
响应外层统一如下,后文的“输出”放在 `data` 中:
|
||
|
||
```json
|
||
{"ok":true,"code":"OK","message":"","request_id":"<本次请求UUID>","server_time_ms":1789092000000,"recovery_action":"NONE","retry_after_ms":0,"data":{}}
|
||
```
|
||
|
||
## 一、后台预登记:运维后台或生产工装调用
|
||
|
||
### 1. 登记一台生产设备
|
||
|
||
`POST /api/v1/ops/device-inventory`
|
||
|
||
**用途:** 在平台建立设备档案,生成设备编号和凭据交付任务。MAC、型号、硬件版本用于识别设备;批次用于追溯。另需请求头 `Idempotency-Key`,避免重复建档。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"factory_mac":"AABBCCDDEEFF","hardware_model":"KP01","hardware_revision":"A1","batch_no":"20260911-01"}
|
||
```
|
||
|
||
输出:设备生产编号、平台编号、交付任务和是否放行。
|
||
|
||
```json
|
||
{"device_id":"KP01-AABBCCDDEEFF","platform_device_id":"<平台设备UUID>","enrollment_job_id":"<交付任务UUID>","released":false}
|
||
```
|
||
|
||
### 2. 获取设备认证凭据交付包
|
||
|
||
`POST /api/v1/ops/device-inventory/{id}/credential-deliveries`
|
||
|
||
**用途:** 将设备认证密钥加密交给生产工装。`{id}` 使用上一步的 `platform_device_id`;公钥属于接收工装。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"enrollment_job_id":"<交付任务UUID>","receiver_public_key_pem":"<工装RSA公钥PEM>"}
|
||
```
|
||
|
||
输出:加密交付包。工装解密后可取得 `device_id`、`device_key_b64`、`key_version` 等设备认证资料。
|
||
|
||
```json
|
||
{"algorithm":"RSA-OAEP-SHA256+A256GCM","enrollment_job_id":"<交付任务UUID>","wrapped_key_b64":"<加密的数据密钥>","ciphertext_b64":"<凭据密文>","expires_at_ms":1789092600000}
|
||
```
|
||
|
||
### 3. 确认凭据写入并放行
|
||
|
||
`POST /api/v1/ops/device-inventory/{id}/release`
|
||
|
||
**用途:** 确认设备凭据已写入并读回校验,允许设备开始联网认证。`evidence_ref` 是校验记录的引用。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"enrollment_job_id":"<交付任务UUID>","evidence_ref":"factory-check/20260911/001","expected_key_version":1}
|
||
```
|
||
|
||
输出:该设备已放行。
|
||
|
||
```json
|
||
{"device_id":"KP01-AABBCCDDEEFF","platform_device_id":"<平台设备UUID>","enrollment_job_id":"<交付任务UUID>","released":true}
|
||
```
|
||
|
||
## 二、设备认证与绑定:设备调用
|
||
|
||
### 4. 获取平台时间和注册挑战
|
||
|
||
`POST /api/v1/device/time-challenges`
|
||
|
||
**用途:** 取得可信时间和本次注册需要的一次性凭证。`boot_id` 标识本次启动,`client_nonce` 是设备生成的 16 字节随机数,以 Base64URL 无填充编码。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"device_id":"KP01-AABBCCDDEEFF","key_version":1,"boot_id":"<本次启动UUID>","client_nonce":"<16字节随机数的Base64URL>"}
|
||
```
|
||
|
||
输出:带签名的校时数据包。设备验签并解码后读取 `challenge_id`、`server_time_ms`、`expires_at_ms`,同时核对设备编号、启动编号和随机数。
|
||
|
||
```json
|
||
{"payload_b64":"<校时数据的Base64URL>","mac_hex":"<平台响应签名>"}
|
||
```
|
||
|
||
### 5. 设备注册/启动认证
|
||
|
||
`POST /api/v1/device/register`
|
||
|
||
**用途:** 校验设备身份,记录本次启动和软件版本,返回绑定及激活状态。设备编号通过请求头 `X-Device-ID` 传入。首次联网和重新启动都调用。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"challenge_id":"<上一步challenge_id>","boot_id":"<本次启动UUID>","hardware_model":"KP01","hardware_revision":"A1","firmware_version":"1.0.0","sdk_version":"1.0.0"}
|
||
```
|
||
|
||
输出:协议版本和当前设备状态。下面表示认证通过,但尚未绑定。
|
||
|
||
```json
|
||
{"contract_version":"ONBOARDING-1.2-SAAS","state":{"device_id":"KP01-AABBCCDDEEFF","binding_state":"UNBOUND","activation_state":"NOT_STARTED","next_action":"WAIT_BIND"}}
|
||
```
|
||
|
||
### 6. 创建一次绑定设置会话
|
||
|
||
`POST /api/v1/device/setup-sessions`
|
||
|
||
**用途:** 为本次手机绑定建立临时会话。`local_setup_id` 由设备生成,表示本次设置入口;`transport_profile` 固定为 `LOCAL_WEB`。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"boot_id":"<本次启动UUID>","local_setup_id":"<本次设置入口UUID>","transport_profile":"LOCAL_WEB"}
|
||
```
|
||
|
||
输出:云端会话编号,有效期最长 15 分钟;`poll_after_ms` 表示建议多久后查询状态。
|
||
|
||
```json
|
||
{"setup_id":"<设置会话UUID>","expires_at_ms":1789092900000,"poll_after_ms":2000,"mode":"ENROLL"}
|
||
```
|
||
|
||
### 7. 获取手机绑定页面入口
|
||
|
||
`POST /api/v1/device/handoffs`
|
||
|
||
**用途:** 获取手机绑定页地址和一次性入口令牌。设备生成 `verifier`,将其 SHA256 结果以 Base64URL 无填充编码后,作为 `code_challenge`。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"setup_id":"<设置会话UUID>","local_setup_id":"<本次设置入口UUID>","code_challenge":"<verifier的SHA256结果的Base64URL>"}
|
||
```
|
||
|
||
输出:页面地址、一次性令牌和到期时间。令牌最长 90 秒有效,只能兑换一次;`verifier` 保留在设备侧,由设备一并交给手机。
|
||
|
||
```json
|
||
{"entry_url":"https://saas.example/onboarding/entry","handoff_token":"<一次性令牌>","expires_at_ms":1789092090000}
|
||
```
|
||
|
||
手机实际打开:
|
||
|
||
```text
|
||
https://saas.example/onboarding/entry#token=<handoff_token>&verifier=<设备生成的verifier>
|
||
```
|
||
|
||
### 8. 查询绑定进度/领取平台命令
|
||
|
||
`POST /api/v1/device/poll`
|
||
|
||
**用途:** 设备定期查询是否有人申请绑定,以及是否有激活配置。`known_revision` 是设备已知的状态版本,首次可传 0。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"setup_id":"<设置会话UUID>","boot_id":"<本次启动UUID>","known_revision":0}
|
||
```
|
||
|
||
输出示例:手机已经提交绑定申请,平台要求设备提示用户按键确认。`payload` 中的确认字段用于下一接口。
|
||
|
||
```json
|
||
{"state":{"binding_state":"CLAIM_PENDING"},"command":{"command_id":"<绑定申请UUID>","type":"CONFIRM_CLAIM","expires_at_ms":1789092120000,"payload":{"claim_id":"<绑定申请UUID>","challenge":"<平台按键挑战>","binding_digest":"<平台绑定摘要>","expected_binding_generation":0,"masked_account":"尾号1234"}},"poll_after_ms":2000}
|
||
```
|
||
|
||
没有命令时 `command=null`。绑定后可能返回 `APPLY_ACTIVATION`,其中包含激活任务、配置版本、配置包及校验值;见第四部分。
|
||
|
||
### 9. 设备按键确认绑定
|
||
|
||
`POST /api/v1/device/claim-confirmations`
|
||
|
||
**用途:** 用户真实按下设备确认键后,设备上报确认,平台正式建立归属关系。前四个字段取自上一步命令,`press_event_id` 标识本次实际按键。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"claim_id":"<绑定申请UUID>","challenge":"<平台按键挑战>","binding_digest":"<平台绑定摘要>","expected_binding_generation":0,"press_event_id":"<本次按键事件UUID>"}
|
||
```
|
||
|
||
输出:`BOUND` 表示正式绑定成功;`binding_generation` 是绑定代数,绑定或解绑发生后会变化。
|
||
|
||
```json
|
||
{"claim_id":"<绑定申请UUID>","already_applied":false,"state":{"binding_state":"BOUND","binding_generation":1,"next_action":"RESUME_ACTIVATION"}}
|
||
```
|
||
|
||
### 10. 设备确认已保存绑定结果
|
||
|
||
`POST /api/v1/device/state-acks`
|
||
|
||
**用途:** 设备将最新平台状态保存到本地后回执。状态版本、绑定代数和摘要使用平台返回值;`local_generation` 是本次启动的本地保存序号,不能倒退。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"device_revision":5,"binding_generation":1,"local_generation":1,"state_hash":"<平台返回的state_hash>"}
|
||
```
|
||
|
||
输出:平台已收到保存回执;设备继续查询状态,等允许后关闭临时设置入口。
|
||
|
||
```json
|
||
{"accepted_revision":5,"setup_can_close":false,"close_after_ms":30000,"next_action":"POLL_FOR_CLOSE"}
|
||
```
|
||
|
||
### 11. 关闭本次临时设置入口
|
||
|
||
`POST /api/v1/device/setup-close`
|
||
|
||
**用途:** 绑定流程收尾,关闭临时设置入口。正常完成时等待 `poll` 返回 `setup_can_close=true`,再传 `SUCCESS`;其他原因可为 `TIMEOUT`、`CANCELLED`、`NETWORK_SWITCH`。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"setup_id":"<设置会话UUID>","reason":"SUCCESS","final_revision":5}
|
||
```
|
||
|
||
输出:允许关闭;关闭入口不等于语音激活完成,激活可继续进行。
|
||
|
||
```json
|
||
{"close_allowed":true,"state":{"binding_state":"BOUND"}}
|
||
```
|
||
|
||
## 三、手机绑定页面:SaaS 前端调用
|
||
|
||
用户看到的页面是 `/onboarding/setup`,正常由带一次性凭证的 `/onboarding/entry` 进入。登录账号及目标设备由会话确定,无需前端在绑定请求中再传手机号或设备编号。
|
||
|
||
### 12. 兑换设备提供的一次性入口
|
||
|
||
`POST /api/v1/web/handoffs/exchange`
|
||
|
||
**用途:** 手机用设备提供的令牌和校验值建立绑定会话。服务端通过 Cookie 保持该会话,并返回后续 POST 使用的 `csrf_token`。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"token":"<设备提供的handoff_token>","verifier":"<设备提供的verifier>"}
|
||
```
|
||
|
||
输出:注意此接口的响应 `data` 内还有一层 `data`,这是当前代码的实际结构。
|
||
|
||
```json
|
||
{"csrf_token":"<后续请求使用的CSRF值>","data":{"setup_id":"<设置会话UUID>","device_id":"KP01-AABBCCDDEEFF","sms_enabled":true,"state":{"binding_state":"UNBOUND","binding_generation":0}}}
|
||
```
|
||
|
||
### 13. 发送手机登录验证码
|
||
|
||
`POST /api/v1/web/auth/sms/send`
|
||
|
||
**用途:** 给用户手机号发送登录验证码。`phone_e164` 含国家区号,`purpose` 固定为 `LOGIN`。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"phone_e164":"+8613800000000","purpose":"LOGIN"}
|
||
```
|
||
|
||
输出:验证码任务编号、过期时间、多久后可重发;不会在接口响应中返回验证码。
|
||
|
||
```json
|
||
{"sms_challenge_id":"<短信验证UUID>","expires_at_ms":1789092300000,"resend_after_ms":60000}
|
||
```
|
||
|
||
### 14. 验证短信并登录
|
||
|
||
`POST /api/v1/web/auth/sms/verify`
|
||
|
||
**用途:** 验证用户输入的短信验证码,建立登录状态。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"sms_challenge_id":"<短信验证UUID>","code":"123456"}
|
||
```
|
||
|
||
输出:登录成功,并返回更新后的 CSRF 值;前端后续请求改用该值。
|
||
|
||
```json
|
||
{"csrf_token":"<更新后的CSRF值>","data":{"authenticated":true,"setup_id":"<设置会话UUID>"}}
|
||
```
|
||
|
||
### 15. 查询可以绑定的家庭和使用者
|
||
|
||
`POST /api/v1/web/profiles`
|
||
|
||
**用途:** 列出当前用户有权选择的家庭和设备使用者。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{}
|
||
```
|
||
|
||
输出:家庭和使用者列表。选择目标后,后续绑定使用 `elder_id`。
|
||
|
||
```json
|
||
{"items":[{"household_id":"<家庭UUID>","household_name":"我的家庭","elder_id":"<使用者UUID>","preferred_name":"爸爸"}]}
|
||
```
|
||
|
||
### 16. 创建家庭/设备使用者
|
||
|
||
`POST /api/v1/web/profiles/create`
|
||
|
||
**用途:** 没有可选使用者时创建档案。新建家庭传 `household_name`;已有家庭则改传 `household_id`。`preferred_name` 是使用者称呼。
|
||
|
||
输入示例:新建家庭和使用者。
|
||
|
||
```json
|
||
{"household_name":"我的家庭","preferred_name":"爸爸"}
|
||
```
|
||
|
||
输出:新建的家庭和使用者编号。
|
||
|
||
```json
|
||
{"household_id":"<家庭UUID>","elder_id":"<使用者UUID>"}
|
||
```
|
||
|
||
### 17. 提交设备绑定申请
|
||
|
||
`POST /api/v1/web/claims`
|
||
|
||
**用途:** 申请把当前设备绑定给选中的使用者。`elder_id` 来自上面两个接口,`expected_binding_generation` 来自最新设备状态。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"elder_id":"<使用者UUID>","expected_binding_generation":0}
|
||
```
|
||
|
||
输出:申请编号和状态。`CLAIM_PENDING` 表示等待设备按键确认,还没有正式绑定。
|
||
|
||
```json
|
||
{"claim_id":"<绑定申请UUID>","expires_at_ms":1789092120000,"state":{"binding_state":"CLAIM_PENDING","binding_generation":0}}
|
||
```
|
||
|
||
### 18. 查询手机页面上的绑定进度
|
||
|
||
`POST /api/v1/web/setup/status`
|
||
|
||
**用途:** 手机刷新等待确认、已绑定和激活进度。`device_saved` 表示设备是否已确认保存绑定结果。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{}
|
||
```
|
||
|
||
输出示例:设备已经绑定并保存结果。
|
||
|
||
```json
|
||
{"binding_id":"<正式绑定UUID>","device_saved":true,"authenticated":true,"state":{"device_revision":5,"binding_generation":1,"binding_state":"BOUND"}}
|
||
```
|
||
|
||
### 19. 手机确认已收到绑定成功结果
|
||
|
||
`POST /api/v1/web/setup/ack`
|
||
|
||
**用途:** 告诉平台手机页面已收到绑定成功结果,配合设备完成设置收尾。三个字段均取自上一步响应。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"binding_id":"<正式绑定UUID>","binding_generation":1,"received_revision":5}
|
||
```
|
||
|
||
输出:回执已接收。
|
||
|
||
```json
|
||
{"accepted":true}
|
||
```
|
||
|
||
## 四、绑定后的语音激活:设备继续调用
|
||
|
||
配置由平台后台任务准备,通过前面的 `POST /api/v1/device/poll` 下发。设备不用直接调用供应商注册接口。
|
||
|
||
`poll` 的激活命令输出示例(仍是响应 `data` 内的字段):
|
||
|
||
```json
|
||
{"command":{"command_id":"<激活任务UUID>","type":"APPLY_ACTIVATION","payload":{"activation_id":"<激活任务UUID>","config_version":1,"config_digest":"<配置摘要>","config_b64":"<编码后的配置包>","config_mac":"<配置签名>","key_version":1,"config_saved":false,"engine_initialized":false}}}
|
||
```
|
||
|
||
配置包解码后包含设备编号、绑定代数、配置版本、到期时间、IoT 连接资料、单设备密钥、机器人及 RTC 配置。设备校验后保存,用于连接语音服务。
|
||
|
||
### 20. 确认已保存激活配置
|
||
|
||
`POST /api/v1/device/activation-acks`
|
||
|
||
**用途:** 设备校验并保存配置后回执。任务、版本和摘要取自激活命令;绑定代数取自当前状态。
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"activation_id":"<激活任务UUID>","config_version":1,"binding_generation":1,"local_generation":2,"config_digest":"<配置摘要>"}
|
||
```
|
||
|
||
输出:配置保存已确认。
|
||
|
||
```json
|
||
{"accepted":true,"config_version":1}
|
||
```
|
||
|
||
### 21. 申请执行初始化/首次通话测试
|
||
|
||
`POST /api/v1/device/activation-attempts`
|
||
|
||
**用途:** 执行 SDK 初始化或首次通话测试前,申请本次执行许可。`attempt_id` 由设备生成;`stage` 为 `ENGINE_INIT` 或 `CONVERSATION_TEST`。首次通话必须由用户主动发起,并传 `user_initiated=true`。
|
||
|
||
输入示例:申请初始化 SDK。
|
||
|
||
```json
|
||
{"activation_id":"<激活任务UUID>","config_version":1,"attempt_id":"<本次执行UUID>","stage":"ENGINE_INIT","user_initiated":false}
|
||
```
|
||
|
||
输出:本次执行许可和到期时间。许可最长 120 秒,首次通话测试最长 60 秒。
|
||
|
||
```json
|
||
{"activation_id":"<激活任务UUID>","attempt_id":"<本次执行UUID>","stage":"ENGINE_INIT","permit_token":"<短时执行许可>","permit_expires_at_ms":1789092120000,"maximum_test_seconds":60}
|
||
```
|
||
|
||
### 22. 上报初始化/首次通话测试结果
|
||
|
||
`POST /api/v1/device/activation-results`
|
||
|
||
**用途:** 上报执行结果。`outcome` 为 `SUCCESS`、`DEFINITE_FAILURE` 或 `UNKNOWN`;成功时 `sdk_result` 必须为 0。
|
||
|
||
输入示例:真实首次通话完成后上报成功,`evidence` 引用平台已记录的会话和事件。初始化结果使用 `stage=ENGINE_INIT`,`evidence` 可传 `{}`。
|
||
|
||
```json
|
||
{"activation_id":"<激活任务UUID>","attempt_id":"<首次通话执行UUID>","stage":"CONVERSATION_TEST","sdk_result":0,"outcome":"SUCCESS","evidence":{"conversation_id":"<测试会话UUID>","started_event_id":"<开始事件ID>","first_audio_event_id":"<首音频事件ID>","ended_event_id":"<结束事件ID>"}}
|
||
```
|
||
|
||
输出示例:首次通话验收通过,设备可正常使用。仅初始化成功不会直接返回 `READY`。
|
||
|
||
```json
|
||
{"duplicate":false,"state":{"binding_state":"BOUND","activation_state":"READY","next_action":"ENTER_READY"}}
|
||
```
|
||
|
||
首次通话本身复用既有 `POST /device/v3/agent-sessions` 及会话事件接口;不能只调用本节的结果接口就完成验收。原有通话字段和新增测试许可字段见[实施说明中的首通流程](onboarding-implementation.md#6-激活首通和人工恢复)。
|
||
|
||
## 五、页面恢复和可选操作
|
||
|
||
这些操作按需要使用,不是每次首次绑定都必须调用。
|
||
|
||
| 接口 | 用途 | 输入示例 | 输出示例(响应 data,节选) |
|
||
|---|---|---|---|
|
||
| `GET /api/v1/web/setup/session` | 页面刷新后恢复设置会话,取得新的 CSRF 值 | 无正文,浏览器携带设置 Cookie | `{"csrf_token":"<新CSRF值>","data":{"authenticated":true,"state":{"binding_state":"CLAIM_PENDING"}}}` |
|
||
| `POST /api/v1/web/setup/auth-link` | 使用已有 OIDC 登录状态,作为短信登录的另一种方式 | 正文 `{}`,另带 `Authorization: Bearer <登录令牌>` | `{"csrf_token":"<新CSRF值>","data":{"authenticated":true,"setup_id":"<设置会话UUID>"}}` |
|
||
| `POST /api/v1/web/claims/cancel` | 用户取消自己的待确认绑定申请 | `{"claim_id":"<绑定申请UUID>","expected_binding_generation":0}` | `{"state":{"binding_state":"UNBOUND"}}` |
|
||
| `GET /api/v1/web/onboarding/devices` | 设置完成后,通过登录账号查询已绑定设备 | 无正文,携带账号 Cookie 或 OIDC 登录令牌 | `{"items":[{"device_id":"KP01-AABBCCDDEEFF","activation_state":"READY","household_name":"我的家庭","preferred_name":"爸爸"}]}` |
|
||
|
||
## 最常用字段怎么理解
|
||
|
||
| 字段 | 含义/来源 |
|
||
|---|---|
|
||
| `device_id` | 生产设备编号,例如 `KP01-AABBCCDDEEFF` |
|
||
| `platform_device_id` | 平台设备 UUID,用于后台设备接口中的 `{id}` |
|
||
| `boot_id` | 设备本次启动编号,重启后重新生成 |
|
||
| `setup_id` | 本次临时绑定流程编号,由平台创建 |
|
||
| `elder_id` | 使用者档案编号,由手机选择或创建 |
|
||
| `claim_id` | 待设备按键确认的绑定申请编号 |
|
||
| `binding_id` | 已正式生效的绑定记录编号,由手机状态接口返回 |
|
||
| `binding_generation` | 绑定代数,用于区分绑定、解绑后的不同归属状态 |
|
||
| `device_revision` | 平台状态版本,用于判断拿到的是哪一版状态 |
|
||
| `activation_id` | 激活任务编号,通过设备 `poll` 命令取得 |
|
||
| `attempt_id` | 设备生成的一次初始化或首次通话执行编号 |
|
||
|
||
接口路径与请求字段依据[当前 HTTP 路由](../internal/onboarding/http.go)、[设备流程](../internal/onboarding/setup.go)、[手机流程](../internal/onboarding/web.go)、[短信登录](../internal/onboarding/sms.go)、[激活流程](../internal/onboarding/activation.go)及[生产登记](../internal/onboarding/inventory.go)核对。完整 31 项首次接入操作(含管理、退出和异常处理)见[字段清单](onboarding-api-fields.md)。
|