# 设备端注册、绑定与激活接口说明 更新日期:2026-09-12。 依据原始《AI电话_首次配网注册与激活_完整流程与详细设计(1)》附件 A、B、C、E、I 整理,仅列设备直接调用 SaaS 的 C01~C11。按本次要求省去辅助流程控制字段,不添加原文没有规定的请求或响应字段。 本文件保留字段列表、中文含义、获取来源和示例。服务端已按此接口契约实现,版本为 `ONBOARDING-1.1`,并按本次要求移除三个辅助流程控制字段。实现与验证记录见[接口对齐说明](设备端接口_文档与当前代码差异.md);线上发布结果另见[发布记录](onboarding-release-20260912.md)。 ## 通用规则 - 设备已完成生产登记,持有出厂写入的 `device_id`、32 字节 `device_key`、`key_version`。 - 全部接口使用 POST,正文为 JSON,不带 query 参数;普通报文上限 8 KiB,配置包上限 32 KiB。 - C01 是无可信时间时可通过专用 HTTP 入口调用的校时接口。其余接口使用严格验证证书和主机名的 HTTPS。 - `<…>` 为占位值,必须使用实际返回值或生成值;示例中的编号、版本、时间不是可直接请求线上服务的数据。 - `string` 为字符串,`integer` 为整数,`boolean` 为 true/false,`object` 为 JSON 对象。UUID 按原文为标准 36 字符 UUID v4;Base64URL 无填充编码末尾不带 `=`。 - 版本、计数按原文范围为 0~2147483647,时间为 Unix 毫秒。字段表中的全部输入均为原文必填字段。 ### 请求头 C02~C11 使用下列认证头。C01 的设备编号和密钥版本放在正文中,不要求先提交可信时间戳或普通设备请求签名。 | 字段 | 中文含义 | 怎么获得/填写 | | --- | --- | --- | | `Content-Type` | 正文格式 | 固定 `application/json`,C01 也使用。 | | `X-Device-ID` | 生产设备编号 | 从出厂配置读取,例如 `KP01-AABBCCDDEEFF`。 | | `X-Key-Version` | 设备认证密钥版本 | 从本机已保存凭据读取,十进制填写。 | | `X-Timestamp-Ms` | 本次发送时间 | C01 验证并校时后,读取当前可信 UTC 毫秒时间。 | | `X-Nonce` | 本次发送随机数 | 每次 HTTP 发送生成新的 16 字节安全随机数,做 Base64URL 无填充编码。 | | `X-Request-ID` | 业务请求编号 | 由设备生成 UUID v4;同一次业务操作重试保留,原始正文也保留。 | | `Authorization` | 设备请求认证码 | 使用本机 `device_key` 计算签名,填写 `Device-HMAC-SHA256 <64位小写十六进制HMAC>`。 | 签名按附件 B 的 DEVREQ1 规则计算,以下 9 行以 LF 连接,末尾不再加换行: ```text DEVREQ1 <大写HTTP方法> <实际path> <原始请求正文的SHA256小写十六进制> ``` 密钥使用原始 32 字节,不发送密钥本身。网络重试更新随机数、发送时间和签名,但不重新生成同一操作的业务编号、按键事件编号或执行编号。 ### 普通响应外层 C02~C11 使用此封装,C01 不使用。成功时读取 `data`,失败时读取 `code`、`message`;设备归属和激活结果以业务状态为准。 | 字段 | 类型 | 中文含义 | 来源/怎么用 | | --- | --- | --- | --- | | `ok` | boolean | 本次请求是否成功 | 平台生成;不能单独用它判断设备已完成绑定或激活。 | | `code` | string | 业务结果码 | 平台返回,成功为 `OK`,失败为对应错误码。 | | `request_id` | string(UUID) | 请求追踪编号 | 平台返回与本次请求关联的编号,供查找请求记录。 | | `data` | object | 成功业务输出 | 字段按各接口下表读取。 | | `server_time_ms` | integer | 平台时间 | 平台生成;原文成功响应中提供,不能替代 C01 的首次可信校时。 | | `message` | string | 错误中文说明 | 失败时由平台提供,便于提示原因。 | ```json { "ok": true, "code": "OK", "request_id": "<请求UUID>", "data": {}, "server_time_ms": 1789092000000 } ``` 失败示例: ```json { "ok": false, "code": "CLAIM_EXPIRED", "request_id": "<请求UUID>", "message": "绑定确认已过期,请重新发起" } ``` ### 公共设备状态 `state` 下表相对于 `data.state`。按本次删减后的口径列出,状态版本、绑定代数和摘要必须来自同一版返回状态。 | 字段 | 类型 | 中文含义 | 来源/后续使用 | | --- | --- | --- | --- | | `device_id` | string | 生产设备编号 | 来自平台生产记录,设备与本机编号核对。 | | `device_revision` | integer | 平台设备状态版本 | 由平台维护;后续用于 C05、C07、C11。 | | `binding_generation` | integer | 绑定代数 | 平台随绑定关系变化而更新,初始 0,首次绑定后 1;用于防止旧归属信息被继续使用。 | | `binding_state` | string | 绑定状态 | 平台根据归属关系返回,取值见下表。 | | `activation_state` | string | 激活状态 | 平台根据激活任务返回,只有 READY 表示服务已就绪。 | | `state_hash` | string | 本版状态摘要 | 平台按附件 I.1 计算;设备保存该版状态后在 C07 原样回传。 | | 字段 | 取值及中文含义 | | --- | --- | | `binding_state` | `UNBOUND` 未绑定;`CLAIM_PENDING` 等待按键;`BOUND` 已绑定;`TRANSFER_PENDING` 转移处理中。 | | `activation_state` | `NOT_STARTED` 未开始;`RESERVED` 已预留;`CONTACT_POSSIBLE` 可能已执行;`REGISTERED_OBSERVED` 已确认注册;`READY` 已就绪;`RECONCILE_REQUIRED` 待对账;`BLOCKED` 被阻止。 | `state_hash` 按原文对以下内容以 LF 连接后计算 SHA256,输出小写十六进制,末尾无换行: ```text STATE1 ``` `device_revision` 是平台状态版本,`binding_generation` 是归属代数,`local_generation` 是设备本地保存序号,`config_version` 是激活配置版本;不能互相代填。 ## 接口总览 下面路径前统一加 `/api/v1/device`。 | 编号 | POST 路径 | 用途 | | --- | --- | --- | | C01 | `/time-challenges` | 校时并获取注册挑战 | | C02 | `/register` | 认证设备并登记启动 | | C03 | `/setup-sessions` | 创建设置会话 | | C04 | `/handoffs` | 获取可交给手机的一次性绑定入口 | | C05 | `/poll` | 查询状态及命令 | | C06 | `/claim-confirmations` | 设备按键确认绑定 | | C07 | `/state-acks` | 确认已保存绑定状态 | | C08 | `/activation-attempts` | 申请一次 SDK 执行许可 | | C09 | `/activation-results` | 上报激活执行结果 | | C10 | `/activation-acks` | 确认激活结果已保存 | | C11 | `/setup-close` | 记录设置收尾并关闭入口 | ## C01 校时并取得注册挑战 `POST /api/v1/device/time-challenges` 用途:让设备在时钟不正确时先取得可信时间,再使用严格 HTTPS。只返回时间和挑战,不返回用户资料、登录令牌或火山密钥。 ### 输入字段 | 字段 | 类型 | 必填 | 中文含义 | 怎么获得/填写 | | --- | --- | --- | --- | --- | | `device_id` | string | 是 | 生产设备编号 | 读取出厂配置:`KP01-` 加 12 位大写十六进制 MAC。 | | `key_version` | integer | 是 | 认证密钥版本 | 读取本机保存的凭据版本,不是密钥内容。 | | `boot_id` | string(UUID) | 是 | 本次启动编号 | 设备每次启动生成并保留,后续 C02、C03、C05 沿用。 | | `client_nonce` | string | 是 | 本次校时随机数 | 设备生成 16 字节安全随机数并做 Base64URL 编码,每次校时重试换新值。 | 输入示例: ```json { "device_id": "KP01-AABBCCDDEEFF", "key_version": 1, "boot_id": "<本次启动UUID>", "client_nonce": "<16字节随机数的Base64URL>" } ``` ### 输出字段 下表为校时响应根对象。 | 字段 | 类型 | 中文含义 | 来源/设备怎么用 | | --- | --- | --- | --- | | `payload_b64` | string | 校时数据包 | 平台将下方六个字段序列化并编码;设备用原字符串验签后解码。 | | `mac_hex` | string | 校时数据认证码 | 平台用本设备密钥计算 TIME1 HMAC,设备使用同一密钥验证。 | 输出示例: ```json { "payload_b64": "<校时数据包的Base64URL>", "mac_hex": "<64位小写十六进制HMAC>" } ``` `payload_b64` 验签后解码字段: | 字段 | 类型 | 中文含义 | 来源/怎么用 | | --- | --- | --- | --- | | `device_id` | string | 设备编号回显 | 核对等于本次请求及本机编号。 | | `boot_id` | string(UUID) | 启动编号回显 | 核对等于设备本次启动编号。 | | `client_nonce` | string | 随机数回显 | 核对等于本次新请求的随机数。 | | `challenge_id` | string(UUID) | 注册挑战编号 | 由平台生成并返回,保存后传入 C02。 | | `server_time_ms` | integer | 经过认证的平台时间 | 平台可信时钟生成;全部校验通过后设置设备时钟。 | | `expires_at_ms` | integer | 挑战到期时间 | 平台签发时间加 120 秒,到期后重新 C01。 | ```json { "device_id": "KP01-AABBCCDDEEFF", "boot_id": "<本次启动UUID>", "client_nonce": "<本次请求随机数>", "challenge_id": "<注册挑战UUID>", "server_time_ms": 1789092000000, "expires_at_ms": 1789092120000 } ``` 校验公式:`HMAC-SHA256(device_key, UTF8("TIME1\n" + payload_b64))`,其中 `\n` 表示一个 LF 换行。附件 B 要求设备核对全部回显字段、单调计时 RTT 不超过 10 秒、时间不早于固件或已保存可信时间允许的下限;通过后校时,再开始 HTTPS。 ## C02 设备认证与启动登记 `POST /api/v1/device/register` 用途:认证已有设备身份并登记本次启动;重复请求不新建设备、不清空既有归属。 ### 输入字段 | 字段 | 类型 | 必填 | 中文含义 | 怎么获得/填写 | | --- | --- | --- | --- | --- | | `challenge_id` | string(UUID) | 是 | 注册挑战 | 取 C01 验签后解码对象中的 `challenge_id`。 | | `boot_id` | string(UUID) | 是 | 本次启动编号 | 沿用同一次 C01 的 `boot_id`。 | | `hardware_model` | string,≤32字节 | 是 | 设备型号 | 从出厂配置读取,按真实型号填写。 | | `hardware_revision` | string,≤16字节 | 是 | 硬件版本 | 读取出厂记录的硬件修订号。 | | `firmware_version` | string,≤32字节 | 是 | 固件版本 | 读取设备当前实际运行的固件版本。 | | `sdk_version` | string,≤64字节 | 是 | SDK版本 | 读取设备实际集成的 SDK 版本信息。 | 输入示例: ```json { "challenge_id": "", "boot_id": "<本次启动UUID>", "hardware_model": "KP01", "hardware_revision": "A1", "firmware_version": "1.0.0", "sdk_version": "1.0.0" } ``` ### 输出字段 下表字段位于普通响应的 `data` 中。 | 字段 | 类型 | 中文含义 | 来源/设备怎么用 | | --- | --- | --- | --- | | `state` | object | 当前设备状态 | 平台返回已有记录的最新状态,完整字段见公共状态表。 | | `contract_version` | string | 协议版本 | 原文规定 `ONBOARDING-1.1`;用于确认两侧接口口径。 | 输出示例: ```json { "state": { "device_id": "KP01-AABBCCDDEEFF", "device_revision": 3, "binding_generation": 0, "binding_state": "UNBOUND", "activation_state": "NOT_STARTED", "state_hash": "<本版状态SHA256摘要>" }, "contract_version": "ONBOARDING-1.1" } ``` ## C03 创建设置会话 `POST /api/v1/device/setup-sessions` 用途:为本次设置建立平台会话;已绑定设备可恢复上下文,但不能借此重新认领。 ### 输入字段 | 字段 | 类型 | 必填 | 中文含义 | 怎么获得/填写 | | --- | --- | --- | --- | --- | | `boot_id` | string(UUID) | 是 | 本次启动编号 | 沿用已完成 C02 的启动编号。 | | `local_setup_id` | string(UUID) | 是 | 本地设置编号 | 设备为本次设置流程生成;重试和 C04 沿用。 | | `transport_profile` | string | 是 | 本地交互方式 | 按原文固定传 `LOCAL_WEB`。 | 输入示例: ```json { "boot_id": "<本次启动UUID>", "local_setup_id": "<设备生成的本地设置UUID>", "transport_profile": "LOCAL_WEB" } ``` ### 输出字段 下表字段位于普通响应的 `data` 中。 | 字段 | 类型 | 中文含义 | 来源/设备怎么用 | | --- | --- | --- | --- | | `setup_id` | string(UUID) | 平台设置会话编号 | 平台生成,后续传 C04、C05、C11;不同于设备生成的 local_setup_id。 | | `expires_at_ms` | integer | 设置会话到期时间 | 平台生成;默认 15 分钟,原文绝对上限 30 分钟,设备以返回期限为准。 | | `poll_after_ms` | integer | 建议轮询间隔,毫秒 | 平台返回;绑定期间原文默认 2000。 | | `state` | object | 当前设备状态 | 平台返回,完整字段见公共状态表。 | 输出示例: ```json { "setup_id": "<平台设置会话UUID>", "expires_at_ms": 1789092900000, "poll_after_ms": 2000, "state": { "device_id": "KP01-AABBCCDDEEFF", "device_revision": 3, "binding_generation": 0, "binding_state": "UNBOUND", "activation_state": "NOT_STARTED", "state_hash": "<本版状态SHA256摘要>" } } ``` ## C04 取得一次性手机入口 `POST /api/v1/device/handoffs` 用途:设备取得 SaaS 绑定入口,并交给当前已授权的本地会话。 ### 输入字段 | 字段 | 类型 | 必填 | 中文含义 | 怎么获得/填写 | | --- | --- | --- | --- | --- | | `setup_id` | string(UUID) | 是 | 平台设置会话编号 | 取 C03 的 `data.setup_id`。 | | `local_setup_id` | string(UUID) | 是 | 本地设置编号 | 沿用 C03 请求中的同名字段。 | | `code_challenge` | string | 是 | 入口校验摘要 | 设备生成32字节随机值并编码为 verifier;对 verifier 的 ASCII 字节算 SHA256,再编码为 Base64URL。 | 输入示例: ```json { "setup_id": "", "local_setup_id": "", "code_challenge": "<32字节SHA256结果的Base64URL>" } ``` ### 输出字段 下表字段位于普通响应的 `data` 中。 | 字段 | 类型 | 中文含义 | 来源/设备怎么用 | | --- | --- | --- | --- | | `handoff_token` | string | 一次性入口令牌 | 平台生成32字节随机值并编码;设备把它放进入口链接。 | | `expires_at_ms` | integer | 令牌到期时间 | 平台生成,原文有效期90秒;不能由设备自行延长。 | | `entry_url` | string | SaaS绑定页面地址 | 由平台固定配置的 HTTPS 白名单入口。 | 输出示例: ```json { "handoff_token": "<平台一次性令牌>", "expires_at_ms": 1789092090000, "entry_url": "https://saas.example/onboarding/entry" } ``` 设备自己保留 `verifier`,不是向平台多传一个字段。交给手机的完整链接为: ```text #token=&verifier=<设备生成的verifier> ``` ## C05 查询状态和命令 `POST /api/v1/device/poll` 用途:设备查询当前状态,领取绑定确认命令或激活配置;查询本身不代表用户按键或 SDK 执行完成。 ### 输入字段 | 字段 | 类型 | 必填 | 中文含义 | 怎么获得/填写 | | --- | --- | --- | --- | --- | | `setup_id` | string(UUID) | 是 | 平台设置会话编号 | 取 C03 返回的设置会话编号。 | | `boot_id` | string(UUID) | 是 | 本次启动编号 | 沿用本次已经注册的启动编号。 | | `known_revision` | integer | 是 | 设备已知状态版本 | 取最近返回的 `state.device_revision`;首次不知道时传0。按原文该字段必填。 | 输入示例: ```json { "setup_id": "", "boot_id": "<本次启动UUID>", "known_revision": 3 } ``` ### 输出字段 下表字段位于普通响应的 `data` 中。 | 字段 | 类型 | 中文含义 | 来源/设备怎么用 | | --- | --- | --- | --- | | `state` | object | 当前设备状态 | 平台返回,完整字段见公共状态表。 | | `command` | object 或 null | 当前命令 | 平台产生;没有命令时为 null,原文兼容 NONE 类型。命令子字段见下表。 | | `poll_after_ms` | integer | 下次轮询间隔,毫秒 | 由平台返回;绑定阶段默认2秒,普通待机不保持高频轮询。 | 输出示例: ```json { "state": { "device_id": "KP01-AABBCCDDEEFF", "device_revision": 3, "binding_generation": 0, "binding_state": "UNBOUND", "activation_state": "NOT_STARTED", "state_hash": "<本版状态SHA256摘要>" }, "command": null, "poll_after_ms": 2000 } ``` ### `command` 命令字段 | 字段 | 类型 | 中文含义 | 来源/怎么用 | | --- | --- | --- | --- | | `command_id` | string(UUID) | 命令编号 | 平台生成,设备识别重复命令;原文未规定它必须等于申请或激活任务编号。 | | `type` | string | 命令类型 | 原文为 NONE、CONFIRM_CLAIM、APPLY_ACTIVATION、UPDATE_STATE、CLOSE_SETUP;按返回类型处理。 | | `expires_at_ms` | integer | 命令到期时间 | 平台生成,设备按可信时间判断有效性。 | | `payload` | object | 命令数据 | 由平台生成;下面只展开原文明确给出的两种命令内容。 | `CONFIRM_CLAIM` 的 `payload`: | 字段 | 类型 | 中文含义 | 来源/怎么用 | | --- | --- | --- | --- | | `claim_id` | string(UUID) | 绑定申请编号 | 平台产生,设备从此处获取后传 C06。 | | `challenge` | string | 按键挑战 | 平台生成32字节随机值编码,真实按键后 C06 原样回传。 | | `binding_digest` | string | 固定绑定内容摘要 | 平台计算64位 SHA256 小写十六进制,设备不改写,C06 原样回传。 | | `masked_account` | string | 脱敏账号提示 | 平台生成,例如“尾号1234”,供用户确认当前申请。 | | `expected_binding_generation` | integer | 预期绑定代数 | 平台在建立申请时确定;C06 原样回传。 | ```json { "command_id": "<命令UUID>", "type": "CONFIRM_CLAIM", "expires_at_ms": 1789092120000, "payload": { "claim_id": "<绑定申请UUID>", "challenge": "<32字节随机值的Base64URL>", "binding_digest": "<固定绑定内容SHA256>", "masked_account": "尾号1234", "expected_binding_generation": 0 } } ``` `APPLY_ACTIVATION` 的 `payload` 按原文只列配置封装: | 字段 | 类型 | 中文含义 | 来源/怎么用 | | --- | --- | --- | --- | | `config_b64` | string | 激活配置包 | 平台生成配置 JSON 并编码;设备验签后解码,下方列出解码字段。 | | `config_mac` | string | 配置认证码 | 平台计算 `HMAC-SHA256(device_key, UTF8("CFG1\n" + config_b64))` 的十六进制值;其中 \n 表示一个 LF,设备用本机密钥验证。 | 配置包验签解码后的字段,依据附件 E.2: | 字段 | 类型 | 中文含义 | 来源/怎么用 | | --- | --- | --- | --- | | `contract_version` | string | 配置协议版本 | 原文为 `ONBOARDING-1.1`。 | | `device_id` | string | 配置所属设备 | 平台读取生产记录,设备核对与本机一致。 | | `activation_id` | string(UUID) | 激活任务编号 | 平台创建并保留;设备从配置包中取出,后续 C08、C09、C10 使用。 | | `config_version` | integer | 激活配置版本 | 平台生成;后续 C08、C10 使用,不自行写死。 | | `binding_generation` | integer | 配置对应绑定代数 | 平台维护;与当前公共状态核对,防止使用旧归属配置。 | | `expires_at_ms` | integer | 配置到期时间 | 由平台签发,设备不得用过期配置开始新的首次激活;原文未在此规定统一24小时有效期。 | | `iot` | object | 供应商注册资料 | 平台组装,子字段如下。 | | `iot.instance_id` | string | 供应商实例编号 | 来自平台保存的实例配置。 | | `iot.product_key` | string | 供应商产品标识 | 来自平台保存的产品配置。 | | `iot.product_secret` | string | 受保护的产品注册密钥 | 这是原文 E.2 明确列出的字段;设备通过受保护配置取得,供原文 SDK 注册流程使用;与当前代码方案的差异见单独说明。 | | `iot.device_name` | string | 物理设备在供应商侧的固定名称 | 由 SaaS 首次激活前生成并永久记录,设备原样使用;不随账号、重试、重启更换。 | | `bot_id` | string | 共享智能体编号 | 来自平台配置,设备按对应 SDK 要求使用。 | 原文要求配置仅经设备 HTTPS 下发,落地使用加密 NVS,不交给手机或写入普通日志。该表没有增加当前代码中的其他运行配置字段。 ## C06 设备按键确认绑定 `POST /api/v1/device/claim-confirmations` 用途:用户真实按下设备确认键后,设备提交本次确认,平台正式建立归属关系。 ### 输入字段 | 字段 | 类型 | 必填 | 中文含义 | 怎么获得/填写 | | --- | --- | --- | --- | --- | | `claim_id` | string(UUID) | 是 | 绑定申请编号 | 取 C05 同一确认命令的 `payload.claim_id`。 | | `challenge` | string | 是 | 按键挑战 | 取该命令的 `payload.challenge`,原样回传。 | | `binding_digest` | string,64位hex | 是 | 绑定内容摘要 | 取该命令同名字段,原样回传。 | | `expected_binding_generation` | integer | 是 | 预期绑定代数 | 取该命令同名字段,不能自行加一。 | | `press_event_id` | string(UUID) | 是 | 本次真实按键事件编号 | 设备在真实按键发生时生成并保存,网络重试沿用。 | 输入示例: ```json { "claim_id": "", "challenge": "", "binding_digest": "", "expected_binding_generation": 0, "press_event_id": "<设备实际按键UUID>" } ``` ### 输出字段 下表字段位于普通响应的 `data` 中。 | 字段 | 类型 | 中文含义 | 来源/设备怎么用 | | --- | --- | --- | --- | | `claim_id` | string(UUID) | 已处理的绑定申请 | 平台返回,设备核对是本次申请。 | | `state` | object | 处理后的归属及激活状态 | 平台返回;保存对应版本、代数和摘要后调用 C07。 | | `already_applied` | boolean | 该确认是否已经提交过 | 由平台识别重复相同申请的结果;不可据此产生第二次绑定。 | 输出示例: ```json { "claim_id": "<绑定申请UUID>", "state": { "device_id": "KP01-AABBCCDDEEFF", "device_revision": 4, "binding_generation": 1, "binding_state": "BOUND", "activation_state": "RESERVED", "state_hash": "<本版状态SHA256摘要>" }, "already_applied": false } ``` ## C07 确认绑定状态已保存 `POST /api/v1/device/state-acks` 用途:报告设备已经保存平台状态,不根据此回执修改 owner。 ### 输入字段 | 字段 | 类型 | 必填 | 中文含义 | 怎么获得/填写 | | --- | --- | --- | --- | --- | | `device_revision` | integer | 是 | 已保存状态版本 | 取同一版 `state.device_revision`。 | | `binding_generation` | integer | 是 | 已保存绑定代数 | 取同一版 `state.binding_generation`。 | | `local_generation` | integer | 是 | 本地保存序号 | 由设备本地保存模块产生并在保存成功后记录,不用平台版本号代替。 | | `state_hash` | string,64位hex | 是 | 已保存状态摘要 | 取同一版 `state.state_hash` 并核对实际保存内容。 | 输入示例: ```json { "device_revision": 4, "binding_generation": 1, "local_generation": 1, "state_hash": "<已保存状态摘要>" } ``` ### 输出字段 下表字段位于普通响应的 `data` 中。 | 字段 | 类型 | 中文含义 | 来源/设备怎么用 | | --- | --- | --- | --- | | `accepted_revision` | integer | 平台接受的保存版本 | 平台确认后返回,设备可记录该版已完成回执。 | | `setup_can_close` | boolean | 是否可以收尾 | 平台根据回执和流程条件判断;设备按结果执行收尾。 | 输出示例: ```json { "accepted_revision": 4, "setup_can_close": false } ``` 原文收尾条件:页面与设备都确认后等待3秒,或设备确认后最多30秒。这里保留原文的布尔判断,不新增等待时间或后续动作字段。 ## C08 申请 SDK 执行许可 `POST /api/v1/device/activation-attempts` 用途:平台先记录本次可能执行的事实,再决定是否允许本次 SDK 调用,避免不确定结果下重复执行。 ### 输入字段 | 字段 | 类型 | 必填 | 中文含义 | 怎么获得/填写 | | --- | --- | --- | --- | --- | | `activation_id` | string(UUID) | 是 | 激活任务编号 | 从 C05 激活配置包解码后的 `activation_id` 取得。 | | `config_version` | integer | 是 | 本次使用的配置版本 | 从同一份已验证配置的 `config_version` 取得。 | | `attempt_id` | string(UUID) | 是 | 一次 SDK 执行编号 | 设备为本次实际执行生成并保留;本次请求重试沿用,不重新申请第二次执行。 | 输入示例: ```json { "activation_id": "<配置包中的激活任务UUID>", "config_version": 1, "attempt_id": "<设备生成的执行UUID>" } ``` ### 输出字段 下表字段位于普通响应的 `data` 中。 | 字段 | 类型 | 中文含义 | 来源/设备怎么用 | | --- | --- | --- | --- | | `allowed` | boolean | 是否允许本次执行 | 平台判断后返回;只有 true 才能开始此次 SDK 调用。 | | `attempt_id` | string(UUID) | 许可对应执行编号 | 平台返回本次执行编号,后续 C09 使用。 | | `permit_expires_at_ms` | integer | 许可到期时间 | 原文 I.1 规定许可有效期30秒;超窗重新查询,不能推断先前调用一定没有执行。 | | `state` | object | 当前设备状态 | 平台返回,完整字段见公共状态表。 | 输出示例: ```json { "allowed": true, "attempt_id": "<本次执行UUID>", "permit_expires_at_ms": 1789092030000, "state": { "device_id": "KP01-AABBCCDDEEFF", "device_revision": 5, "binding_generation": 1, "binding_state": "BOUND", "activation_state": "CONTACT_POSSIBLE", "state_hash": "<本版状态SHA256摘要>" } } ``` ## C09 上报激活执行结果 `POST /api/v1/device/activation-results` 用途:上报已获许可的实际 SDK 执行结果。超时或无法确定结果时上报 UNKNOWN,不能当作明确失败重复执行。 ### 输入字段 | 字段 | 类型 | 必填 | 中文含义 | 怎么获得/填写 | | --- | --- | --- | --- | --- | | `activation_id` | string(UUID) | 是 | 激活任务编号 | 沿用 C08 所属任务编号。 | | `attempt_id` | string(UUID) | 是 | 实际执行编号 | 沿用 C08 已申请并返回的执行编号,不在上报时重新生成。 | | `stage` | string | 是 | 执行阶段 | 按原文 I.1 填 `SDK_REGISTER` 或 `CONVERSATION_TEST`,由设备依据本次实际执行操作确定。 | | `sdk_result` | integer | 是 | SDK返回码 | 读取本次实际 SDK 调用或回调结果,不编造结果码。 | | `outcome` | string | 是 | 本次结果分类 | 原文取值:`SUCCESS_OBSERVED` 已观察到成功、`DEFINITE_FAILURE` 明确失败、`UNKNOWN` 未知。 | 输入示例: ```json { "activation_id": "<激活任务UUID>", "attempt_id": "", "stage": "SDK_REGISTER", "sdk_result": 0, "outcome": "SUCCESS_OBSERVED" } ``` ### 输出字段 下表字段位于普通响应的 `data` 中。 | 字段 | 类型 | 中文含义 | 来源/设备怎么用 | | --- | --- | --- | --- | | `activation_id` | string(UUID) | 结果所属任务 | 平台返回,设备与本次任务核对。 | | `state` | object | 处理后的设备状态 | 平台返回,判断仍在激活、待处理或已 READY。 | | `reconcile_required` | boolean | 是否需要对账 | 平台根据本次结果判定;true 时不要自行开始第二次同类激活执行。 | 输出示例: ```json { "activation_id": "<激活任务UUID>", "state": { "device_id": "KP01-AABBCCDDEEFF", "device_revision": 6, "binding_generation": 1, "binding_state": "BOUND", "activation_state": "REGISTERED_OBSERVED", "state_hash": "<本版状态SHA256摘要>" }, "reconcile_required": false } ``` 首次通话测试时使用 `stage=CONVERSATION_TEST`。结果分类只表示这一次执行的事实,不等同于设备最终状态;服务是否可用仍读取 `state.activation_state`。 ## C10 确认激活结果已保存 `POST /api/v1/device/activation-acks` 用途:设备确认激活结果已在本地保存;重复相同回执不产生新的激活副作用。 ### 输入字段 | 字段 | 类型 | 必填 | 中文含义 | 怎么获得/填写 | | --- | --- | --- | --- | --- | | `activation_id` | string(UUID) | 是 | 已保存结果所属任务 | 沿用配置包及 C09 对应的激活任务编号。 | | `local_generation` | integer | 是 | 本地保存序号 | 由设备保存模块在本次结果保存成功后记录,不使用配置版本代替。 | | `config_version` | integer | 是 | 结果对应配置版本 | 沿用本次激活实际使用的配置包版本。 | 输入示例: ```json { "activation_id": "<激活任务UUID>", "local_generation": 2, "config_version": 1 } ``` ### 输出字段 下表字段位于普通响应的 `data` 中。 | 字段 | 类型 | 中文含义 | 来源/设备怎么用 | | --- | --- | --- | --- | | `accepted` | boolean | 回执是否被接受 | 由平台验证后返回。 | | `state` | object | 当前设备状态 | 平台返回,完整字段见公共状态表。 | 输出示例: ```json { "accepted": true, "state": { "device_id": "KP01-AABBCCDDEEFF", "device_revision": 6, "binding_generation": 1, "binding_state": "BOUND", "activation_state": "REGISTERED_OBSERVED", "state_hash": "<本版状态SHA256摘要>" } } ``` ## C11 设置流程收尾 `POST /api/v1/device/setup-close` 用途:请求或报告本次设置流程收尾。关闭临时入口不清空已提交的绑定或激活任务。 ### 输入字段 | 字段 | 类型 | 必填 | 中文含义 | 怎么获得/填写 | | --- | --- | --- | --- | --- | | `setup_id` | string(UUID) | 是 | 要关闭的设置会话 | 取本次 C03 返回的 `setup_id`。 | | `reason` | string | 是 | 关闭原因 | 设备按实际情况填 SUCCESS、TIMEOUT、CANCELLED 或 NETWORK_SWITCH。 | | `final_revision` | integer | 是 | 关闭前最后收到的状态版本 | 取最后成功收到的 `state.device_revision`,不是设备本地保存序号。 | 输入示例: ```json { "setup_id": "", "reason": "SUCCESS", "final_revision": 6 } ``` ### 输出字段 下表字段位于普通响应的 `data` 中。 | 字段 | 类型 | 中文含义 | 来源/设备怎么用 | | --- | --- | --- | --- | | `close_allowed` | boolean | 是否允许关闭 | 平台判定并返回,设备据此执行关闭。 | | `state` | object | 当前设备状态 | 平台返回并保留正式绑定及激活事实,便于后续恢复。 | 输出示例: ```json { "close_allowed": true, "state": { "device_id": "KP01-AABBCCDDEEFF", "device_revision": 6, "binding_generation": 1, "binding_state": "BOUND", "activation_state": "REGISTERED_OBSERVED", "state_hash": "<本版状态SHA256摘要>" } } ``` ## 字段从哪里取得 | 要使用的字段 | 取值来源 | | --- | --- | | `device_id`、`device_key`、`key_version` | 设备出厂写入的身份及凭据。 | | `boot_id` | 设备每次启动生成。 | | `challenge_id` | C01 验签后的校时包。 | | `local_setup_id` | 设备为一次本地设置生成。 | | `setup_id` | C03 平台返回。 | | `claim_id`、`challenge`、`binding_digest`、预期绑定代数 | 同一条 C05 确认命令,不跨命令拼接。 | | `press_event_id` | 设备真实按键时生成。 | | `activation_id`、`config_version` | C05 激活配置包验签解码后取得。 | | `attempt_id` | 设备为一次 SDK 执行生成,C08 申请、C09 沿用。 | | `local_generation` | 设备保存模块记录本地保存完成的序号。 | | `device_revision`、`binding_generation`、`state_hash` | 平台返回的同一版公共状态。 | ## 平台如何确定 C08 执行阶段 C08 不增加阶段字段。平台按任务中已确认的事实判定:尚未观察到注册成功时,许可用于 `SDK_REGISTER`;已注册且 C10 确认保存后,许可用于 `CONVERSATION_TEST`。C09 的阶段必须匹配平台为该执行编号记录的阶段。已完成 READY 的同代绑定不再发放首次激活许可。 原文未给出部分命令的完整 payload,当前实际下发 `CONFIRM_CLAIM`、`APPLY_ACTIVATION` 两种命令,其余保留枚举不作为新增接口功能。 来源:[原始流程文档](),重点是附件 B(认证及校时)、C(设备接口)、E(状态和配置)、I.1(逐接口输入与输出)。