openapi: 3.1.0 info: title: 小程序原生登录与自动蓝牙连接 version: 2.0.1 description: HTTPS;POST 必须携带 UUID v4 X-Request-ID。响应使用 ok/code/request_id/server_time_ms/data 信封。不发 Cookie,不使用 AppSecret 或云开发。现有网页 Origin/CSRF 规则不变。 paths: /api/v1/mini/login/session: post: summary: 创建20分钟原生登录会话 security: [] requestBody: required: true content: application/json: schema: type: object additionalProperties: false required: [portal] properties: portal: {type: string, enum: [customer, operator]} responses: '200': {description: 'data: {login_token: realm.opaque, expires_in: 1200, sms_enabled: boolean}'} default: {description: 参数错误、限流或服务异常} /api/v1/mini/login/captcha: post: summary: 获取图形验证码 security: [{MiniLogin: []}] requestBody: {$ref: '#/components/requestBodies/Empty'} responses: '200': {description: 'data: {captcha_id, image: PNG data URL, expires_at_ms}'} default: {description: 登录会话失效或限流} /api/v1/mini/login/password: post: summary: 使用已有手机号密码登录,不自动注册或提升权限 description: 设备未通过短信验证或验证已过期时返回 403 NEW_DEVICE_SMS_REQUIRED。先完成 LOGIN 短信验证,再将返回的 trusted_device_token 按服务地址、账号和 portal 保存在客户端,后续密码登录携带。设备验证最长 30 天,不代替密码或人机验证。 security: [{MiniLogin: []}] requestBody: required: true content: application/json: schema: type: object additionalProperties: false required: [phone_e164, password, captcha_id] anyOf: - required: [captcha_code] - required: [captcha_ticket] properties: phone_e164: {type: string} password: {type: string, maxLength: 256} trusted_device_token: {type: string, maxLength: 43, writeOnly: true} captcha_id: {type: string, format: uuid} captcha_code: {type: string, pattern: '^[0-9]{6}$'} captcha_ticket: {type: string, maxLength: 4096, writeOnly: true} responses: '200': {description: 'data: {access_token: realm.opaque, portal: customer|operator, expires_in: 86400};会话只能成功消费一次'} default: {description: 验证码或密码错误、账号不可用或限流} /api/v1/mini/login/sms/send: post: summary: 小程序发送手机号登录验证码 description: 与 SaaS 网页、设备绑定入口共用腾讯云短信通道、手机号发送限额和 6 位验证码规则;需先调用 login/captcha。不会返回验证码。 security: [{MiniLogin: []}] requestBody: required: true content: application/json: schema: {$ref: './onboarding.yaml#/components/schemas/SMSSendInput'} responses: '200': {description: 'data: {sms_challenge_id, expires_at_ms, resend_after_ms}'} default: {description: 图片验证码错误、发送失败、登录会话失效或限流} /api/v1/mini/login/sms/verify: post: summary: 小程序验证短信并获得原生登录令牌 description: 客户可按唯一自注册租户配置创建普通账号;管理账号必须预先绑定手机号。挑战与小程序登录会话绑定,成功后一次性消费,不发 Cookie。成功响应另含 trusted_device_token 和 trusted_device_expires_in(2592000 秒),供此设备后续密码登录使用。 security: [{MiniLogin: []}] requestBody: required: true content: application/json: schema: {$ref: './onboarding.yaml#/components/schemas/SMSVerifyInput'} responses: '200': {description: 'data: {access_token: realm.opaque, portal: customer|operator, expires_in: 86400}'} default: {description: 验证码错误、过期、账户不可用或登录会话失效} /api/v1/mini/account: get: summary: 校验原生登录状态 security: [{Mini: []}] responses: '200': {description: 'data: {authenticated: true, portal, display_name}'} default: {description: 登录已过期、撤销或账号被停用} /api/v1/mini/logout: post: summary: 撤销当前原生会话 security: [{Mini: []}] requestBody: {$ref: '#/components/requestBodies/Empty'} responses: '200': {description: 'data: {signed_out: true}'} default: {description: 登录失效或服务异常} /api/v1/mini/ble-session: post: deprecated: true summary: 自动建立设备加密连接,无需手动输入设备编号或配网密码 security: [{Mini: []}] description: 仅允许有设备租户内家庭管理权限的家庭账号和未绑定设备。验证设备随机连接证明,返回本次连接专用 SRP 密码;绝不返回工厂密钥或标签配网密码。 requestBody: required: true content: application/json: schema: type: object additionalProperties: false required: [device_id, model, key_version, client_nonce, server_nonce, proof] properties: device_id: {type: string, pattern: '^KP01-[0-9A-F]{12}$'} model: {type: string} key_version: {type: integer, minimum: 1} client_nonce: {type: string, pattern: '^[A-Za-z0-9_-]{22}$'} server_nonce: {type: string, pattern: '^[A-Za-z0-9_-]{22}$'} proof: {type: string, pattern: '^[a-f0-9]{64}$'} responses: '200': {description: 'data: {device_id, model, session_password: 64字符小写十六进制};只在当前蓝牙连接内有效'} default: {description: 设备或家庭权限不满足、重放证明或绑定暂停} /api/v1/mini/ble-device-state: post: summary: 查询设备账号归属及管理权限;未添加的设备不要求家庭或老人(明文BLE v2) description: 按实际失败条件返回独立 code 和中文 message,不再合并为 DEVICE_UNAVAILABLE。错误信封含 ok=false、code、message、request_id;不包含其他账号身份或老人资料。详见 docs/device-ble-errors-20260918.md。 security: [{Mini: []}] requestBody: required: true content: application/json: schema: type: object additionalProperties: false required: [device_id] properties: device_id: {type: string, pattern: '^KP01-[0-9A-F]{12}$'} responses: '200': {description: 'data: {device_id, id: 平台设备UUID, model, bound: boolean};bound表示已有账号或老人归属,true时只更新Wi-Fi,不申请bind_token'} '400': {description: 'DEVICE_ID_INVALID:设备编号格式错误'} '403': {description: 'ACCOUNT_NOT_FOUND / ACCOUNT_DISABLED / ACCOUNT_DELETED / CUSTOMER_REQUIRED / DEVICE_TENANT_MISMATCH / TENANT_INACTIVE / DEVICE_REVOKED / DEVICE_LOST / DEVICE_QUARANTINED / DEVICE_OWNED_BY_OTHER_ACCOUNT / DEVICE_MANAGE_PERMISSION_REQUIRED;message 提供具体原因及处理方式'} '404': {description: 'DEVICE_NOT_REGISTERED:平台没有该设备的注册记录'} '409': {description: 'DEVICE_NOT_RELEASED:尚未出厂放行;DEVICE_ENROLLMENT_UNSUPPORTED:尚未启用蓝牙实体确认绑定;DEVICE_BINDING_STALE:归属记录与当前设备状态不一致'} default: {description: 参数错误、登录失效、限流或服务异常} /api/v1/device/ble-state: post: summary: 设备用工厂HMAC查询自身是否已绑定,只读,不改变归属 security: [{DeviceHMAC: []}] requestBody: {$ref: '#/components/requestBodies/Empty'} responses: '200': {description: 'data: {bound: boolean};设备仅在true时保存空bind_token任务的新Wi-Fi'} default: {description: 工厂鉴权失败、设备不可用、限流或服务异常} /api/v1/mini/ble-bind-tokens: post: summary: 为当前客户账号签发5分钟设备绑定令牌,无需先创建家庭或老人 description: 设备和账号校验使用与 ble-device-state 相同的具体错误码及提示。另有 ELDER_ID_INVALID(400,显式老人编号格式错误)及 ALREADY_BOUND(409,已有归属,无需重复添加)。 security: [{Mini: []}] requestBody: $ref: './ble-binding.yaml#/paths/~1api~1v1~1web~1ble-bind-tokens/post/requestBody' responses: '200': {description: 'data: {bind_token};设备已有归属或使用者无管理权限时拒绝'} default: {description: 请求无效、登录失效、权限不足或限流} /api/v1/mini/ble-bind-status: post: summary: 查询当前账号签发的绑定令牌结果 security: [{Mini: []}] requestBody: {$ref: './ble-binding.yaml#/components/requestBodies/Token'} responses: '200': {description: 'data: {status: pending|success|failed, message?};蓝牙断开后仍可查询'} default: {description: 请求无效、登录失效或令牌不可访问} /api/v1/mini/device-subject: post: summary: 将已添加到当前账号的设备绑定给有管理权限的老人 security: [{Mini: []}] parameters: - in: header name: X-Request-ID required: true schema: {type: string, format: uuid} requestBody: required: true content: application/json: schema: type: object additionalProperties: false required: [device_id, elder_id, expected_account_binding_id] properties: device_id: {type: string, format: uuid, description: 设备列表中的平台UUID,不是工厂编号} elder_id: {type: string, format: uuid} expected_account_binding_id: {type: string, format: uuid, description: 设备列表返回的account_binding_id} responses: '200': {description: 'data: {status: success, device_id, elder_id};同一有效归属和同一老人可安全重试,不重复注册火山'} '403': {description: 非设备归属账号、无老人管理权限、跨组织或归属已失效} '409': {description: 设备有待确认操作或升级} default: {description: 参数错误、登录失效、限流或服务异常} components: securitySchemes: DeviceHMAC: {type: apiKey, in: header, name: Authorization, description: 'Device-HMAC-SHA256 hex;还需X-Device-ID、X-Key-Version、X-Timestamp-Ms、X-Nonce、X-Request-ID,详见docs/device-mini-ble-v2.md'} Mini: {type: apiKey, in: header, name: Authorization, description: 'Mini 后接 customer.或operator.开头的原生access_token。业务接口仍按原资源白名单和服务器权限验证。'} MiniLogin: {type: apiKey, in: header, name: Authorization, description: 'MiniLogin 后接 login_token,仅允许验证码和密码登录接口。'} requestBodies: Empty: required: true content: application/json: schema: {type: object, additionalProperties: false}