This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
# 设备相关外部接口表
|
||||
|
||||
范围仅包含设备终端以 HMAC 身份直接调用的 `/device/v2/*` 外部接口;不包含家庭/运营 Web API、内部工具和供应商回调。基于 `openapi/openapi.yaml`(OpenAPI 3.1,版本 0.70.0)生成,并与 `internal/httpapi/router.go` 的实际路由逐项核对。当前共 **16** 个已注册且纳入 OpenAPI 契约的接口。
|
||||
|
||||
说明:`*` 表示必填字段;`body` 表示请求体;响应栏只展开成功响应。全部接口都要求设备 HMAC 请求头:`X-Device-Id`、`X-Device-Timestamp`、`X-Device-Nonce`、`X-Device-Content-SHA256`、`X-Device-Signature`,表内不重复。通用错误响应为 `ErrorResponse`。
|
||||
|
||||
## 设备端 v2
|
||||
|
||||
| 接口名字 | 方法与路径 | 接口描述 | 输入参数 | 输出参数 |
|
||||
|---|---|---|---|---|
|
||||
| `getDeviceBootstrap` | `GET /device/v2/bootstrap` | 返回可信设备状态、服务器时间、绑定和最低安全版本 | query `firmware_version*`: string<br>query `board_rev`: string<br>query `rtc_sdk_version`: string<br>query `codec`: string<br>query `sample_rate`: integer<br>query `device_time*`: string(date-time)<br>query `network`: string | 200 DeviceBootstrapResponse{data*:DeviceBootstrapData{clock_skew_ms*:integer(int64), device*:DeviceBootstrap, server_time*:string(date-time)}, request_id*:string} — 返回可信设备状态、服务器时间、绑定和最低安全版本 |
|
||||
| `pullDeviceCommands` | `GET /device/v2/commands` | 返回未过期的待执行命令并记录投递次数 | query `limit`: integer | 200 DeviceCommandDeliveryListResponse{data*:object{items*:array<DeviceCommandDelivery>}, request_id*:string} — 返回未过期的待执行命令并记录投递次数 |
|
||||
| `acknowledgeDeviceCommand` | `POST /device/v2/commands/{id}/ack` | 回执已保存 | path `id*`: string(uuid)<br>body* `application/json` DeviceCommandAckRequest{result_summary*:object, status*:string[ACKNOWLEDGED/SUCCEEDED/FAILED]} | 200 DeviceCommandDeliveryResponse{data*:DeviceCommandDelivery{created_at*:string(date-time), delivery_attempts*:integer, expires_at*:string(date-time), id*:string(uuid), payload*:object, status*:DeviceCommandStatus, type*:string[apply_config/reboot/diagnostics/firmware_update]}, request_id*:string} — 回执已保存 |
|
||||
| `getDeviceConfig` | `GET /device/v2/config` | 返回设备期望配置及当前绑定 | header `If-None-Match`: string | 200 DeviceConfigResponse{data*:DeviceConfiguration{binding*:DeviceBinding, desired_config*:object, device_id*:string(uuid), reported_revision:integer(int64), revision*:integer(int64)}, request_id*:string};headers{ETag:string} — 返回设备期望配置及当前绑定<br>304 无响应体 — 配置未变化 |
|
||||
| `createDeviceConversation` | `POST /device/v2/conversations` | 分配房间和短期入房凭证;此步骤不启动语音智能体。 | header `Idempotency-Key*`: string<br>body* `application/json` CreateConversationRequest{capabilities*:DeviceCapabilities{audio_tracks*:array<string[near/far]>, rtc*:boolean, rtc_credential_renewal:boolean, upload_resume*:boolean}, device_time*:string(date-time), monotonic_ms:integer(int64), network*:DeviceNetwork{rssi:integer, type*:string}, requested_goal*:string} | 201 CreateConversationResponse{data*:CreatedConversation{conversation_id*:string(uuid), privacy*:ConversationPrivacy, rtc*:RTCGrant, session*:ConversationSession, status*:string}, request_id*:string};headers{Idempotency-Replayed:string[true]} — 房间资料已分配;重复请求返回相同通话和相同确定性短期Token |
|
||||
| `getDeviceConversationState` | `GET /device/v2/conversations/{id}` | 设备确认入房后读取云端权威通话状态和下一步动作;供应商永久拒绝启动或异步启动失败时返回稳定failure_code及leave_room,响应不包含供应商原始错误。 | path `id*`: string(uuid) | 200 DeviceConversationStateResponse{data*:DeviceConversationState{action*:string[wait/continue/leave_room], conversation_id*:string(uuid), failure_code:string, status*:ConversationStatus}, request_id*:string} — 返回当前设备所属通话的权威状态和设备动作 |
|
||||
| `activateDeviceConversation` | `POST /device/v2/conversations/{id}/activate` | 设备确认已进入指定RTC房间后,投递固定供应商语音任务。 | path `id*`: string(uuid)<br>header `Idempotency-Key*`: string<br>body* `application/json` ActivateConversationRequest{config_revision*:integer(int64), connection_reference:string, joined_at*:string(date-time), room_id*:string, rtc_join_result*:string, rtc_user_id*:string} | 202 ActivateConversationResponse{data*:ActivatedConversation{accepted_at*:string(date-time), conversation_id*:string(uuid), status*:string[STARTING_AGENT/ACTIVE]}, request_id*:string} — 入房确认已接受;语音智能体正在启动或已经启动 |
|
||||
| `heartbeatDeviceConversation` | `POST /device/v2/conversations/{id}/heartbeat` | 按严格递增序号刷新设备在线状态和通话短期租约;重复或乱序心跳不会延长租约。 | path `id*`: string(uuid)<br>body* `application/json` HeartbeatConversationRequest{command_results*:array<object>, conversation_status*:string[PREPARING/ROOM_ISSUED/STARTING_AGENT/ACTIVE/STOPPING/COMPLETED/FAILED/EXPIRED], device_time*:string(date-time), firmware_version*:string, last_error:string, monotonic_ms*:integer(int64), network*:DeviceNetwork{rssi:integer, type*:string}, recording_queue*:RecordingQueue{failed_segments*:integer, last_failure_at:string(date-time), last_failure_code:string, pending_segments*:integer}, reported_config_revision*:integer(int64), rtc*:RTCHeartbeat{downlink*:boolean, joined*:boolean, uplink*:boolean}, rtc_credential_expires_at:string(date-time), sequence_no*:integer(int64)} | 200 HeartbeatConversationResponse{data*:HeartbeatResult{actions*:array<HeartbeatAction>, commands*:array<object>, desired_config_revision*:integer(int64), lease_expires_at:string(date-time)}, request_id*:string} — 心跳已接受,或已按序号判定为安全重放/乱序请求 |
|
||||
| `stopDeviceConversation` | `POST /device/v2/conversations/{id}/stop` | 记录设备挂断并可靠停止固定供应商任务;重复执行不产生第二个外部副作用。 | path `id*`: string(uuid)<br>header `Idempotency-Key*`: string<br>body* `application/json` StopConversationRequest{device_time*:string(date-time), last_heartbeat_sequence*:integer(int64), reason*:string, recording*:StopRecording{far_segments*:integer, near_segments*:integer}, rtc_left*:boolean} | 202 StopConversationResponse{data*:StoppedConversation{accepted_at*:string(date-time), conversation_id*:string(uuid), status*:string[STOPPING/COMPLETED/FAILED/EXPIRED]}, request_id*:string};headers{Idempotency-Replayed:string[true]} — 停止请求已接受,或通话已经处于停止中/终态 |
|
||||
| `submitDeviceConversationTurns` | `POST /device/v2/conversations/{id}/turns:batch` | 当供应商最终转写缺失时由当前通话所属终端批量补传终稿;平台按turn_key和sequence_no与已有供应商终稿原子去重合并,任一内容冲突会拒绝整批请求。 | path `id*`: string(uuid)<br>header `Idempotency-Key*`: string<br>body* `application/json` DeviceTranscriptBatchRequest{turns*:array<DeviceFinalTurn>} | 200 DeviceTranscriptBatchResponse{data*:DeviceTranscriptBatchResult{accepted_count*:integer, conversation_id*:string(uuid), duplicate_count*:integer}, request_id*:string};headers{Idempotency-Replayed:string[true]} — 整批终稿已合并;完全相同的已有终稿计入duplicate_count而不重复保存 |
|
||||
| `prepareMediaUploadBatch` | `POST /device/v2/conversations/{id}/upload-batches` | 设备提交near/far录音分片清单;业务API仅返回单对象短期PUT地址,不接收录音字节。 | path `id*`: string(uuid)<br>header `Idempotency-Key*`: string<br>body* `application/json` PrepareMediaUploadBatchRequest{segments*:array<MediaSegmentDeclaration>} | 201 MediaUploadBatchResponse{data*:MediaUploadBatch{conversation_id*:string(uuid), expected_total_size*:integer(int64), expires_at*:string(date-time), id*:string(uuid), last_error_code:string, rejected_count*:integer, segment_count*:integer, segments*:array<MediaSegment>, status*:string[PENDING/UPLOADING/VERIFYING/COMPLETED/FAILED/EXPIRED], verification_attempts*:integer, verified_count*:integer}, request_id*:string} — 返回尚未验证分片的10至20分钟单对象上传地址 |
|
||||
| `getDeviceFirmwareDownload` | `GET /device/v2/firmware-releases/{id}/download` | 仅向当前灰度目标签发 5 分钟有效的私有下载地址 | path `id*`: string(uuid) | 200 application/json `{download_url*:string(uri), download_until*:string(date-time)}`;header `Cache-Control: no-store` |
|
||||
| `acknowledgeLocalMediaDelete` | `POST /device/v2/media-segments/{id}/local-delete-ack` | 设备在平台给出的local_delete_after之后删除本地密文并回报结果;该操作不删除云端已验证对象,DELETED重复回报幂等。 | path `id*`: string(uuid)<br>body* `application/json` LocalMediaDeleteReceiptRequest{error_code:string, status*:string[DELETED/FAILED]} | 200 MediaSegmentResponse{data*:MediaSegment{codec*:string, content_type*:string, duration_ms*:integer, expected_digest*:string, expected_size*:integer(int64), id*:string(uuid), last_error_code:string, local_delete_after:string(date-time), local_delete_error_code:string, local_delete_reported_at:string(date-time), local_delete_status:string[DELETED/FAILED], sequence_no*:integer, status*:string[DECLARED/AUTHORIZED/UPLOADED/VERIFYING/VERIFIED/REJECTED/DELETED], track*:string[near/far], upload_until:string(date-time), upload_url:string(uri), verified_at:string(date-time)}, request_id*:string} — 已保存本地删除回执 |
|
||||
| `submitDeviceTelemetry` | `POST /device/v2/telemetry:batch` | 当前签名设备批量上报状态、有限错误码和命令执行结果;平台以设备内event_key和sequence_no原子去重,更新设备影子、命令状态和与当前设备通话关联的异常回收信号。 | header `Idempotency-Key*`: string<br>body* `application/json` DeviceTelemetryBatchRequest{events*:array<DeviceTelemetryEvent>} | 200 DeviceTelemetryBatchResponse{data*:DeviceTelemetryBatchResult{accepted_count*:integer, actions*:array<DeviceTelemetryAction>, desired_config_revision*:integer(int64), duplicate_count*:integer}, request_id*:string};headers{Idempotency-Replayed:string[true]} — 整批遥测已接收;完全相同的已有事件计入duplicate_count |
|
||||
| `getDeviceMediaUploadBatch` | `GET /device/v2/upload-batches/{id}` | 返回分片校验结果;只有VERIFIED分片才包含local_delete_after | path `id*`: string(uuid) | 200 MediaUploadBatchResponse{data*:MediaUploadBatch{conversation_id*:string(uuid), expected_total_size*:integer(int64), expires_at*:string(date-time), id*:string(uuid), last_error_code:string, rejected_count*:integer, segment_count*:integer, segments*:array<MediaSegment>, status*:string[PENDING/UPLOADING/VERIFYING/COMPLETED/FAILED/EXPIRED], verification_attempts*:integer, verified_count*:integer}, request_id*:string} — 返回分片校验结果;只有VERIFIED分片才包含local_delete_after |
|
||||
| `completeMediaUploadBatch` | `POST /device/v2/upload-batches/{id}/complete` | 设备声明本批上传完成,平台可靠投递后台对象校验任务;重复提交不会创建重复任务。 | path `id*`: string(uuid) | 202 MediaUploadBatchResponse{data*:MediaUploadBatch{conversation_id*:string(uuid), expected_total_size*:integer(int64), expires_at*:string(date-time), id*:string(uuid), last_error_code:string, rejected_count*:integer, segment_count*:integer, segments*:array<MediaSegment>, status*:string[PENDING/UPLOADING/VERIFYING/COMPLETED/FAILED/EXPIRED], verification_attempts*:integer, verified_count*:integer}, request_id*:string} — 批次已进入VERIFYING或已经完成 |
|
||||
Reference in New Issue
Block a user