# 哈哈零售API详细文档 ## 序言 ### 概述 以接口的形式对哈哈便利的无人售货柜进行开门、结算、查询业务数据等。 ### 重要说明 **库存管理**:哈哈不维护API商家的库存信息。如商家对库存有要求,请上货时自行保存商品的库存数量,并根据识别结果对库存进行增减。 **业务流程**:用户扫码后商户端自行决定是否可开门(比如判断是否签约免密支付,或者用户余额是否足够)。开门时,设备的开门和关门或者发生错误状态信息,识别完成后,识别的结果,生成订单时,订单信息,都会通过消息通知给商户。商户需要自行免密签约、免密扣款等。所以一般来说,需要商户端开通支付宝和微信的免密支付才能接入本接口。 --- ## 1. 接入前说明 ### 1.1 阅读对象 **定位人群**:哈哈便利接口文档是面向具有一定的网站或APP开发能力,了解 ASP、PHP、JAVA、ASP.NET 等开发语言中的一种及 SQL 数据库语言的网站开发、维护和管理人员。 ### 1.2 接入步骤 #### 步骤1:联系哈哈运营人员开通API功能 联系哈哈运营人员开通您的商家账户的API功能。 #### 步骤2:在商家后台配置回调地址 1. 登录商家后台:http://client.hahabianli.com 2. 进入"API配置"页面 3. 配置回调地址(用于接收开关门通知、识别结果通知、订单通知等) 4. 获取 AppId 和 AppSecret **地址要求**: - 订单回调地址:必须以 http:// 或 https:// 开头,例如:http://www.baidu.com - 消息回调地址:必须以 http:// 或 https:// 开头,用于接收开关门消息、设备异常消息等 ### 1.3 系统交互图 (系统交互流程示意图 - 描述商户系统、哈哈平台、设备之间的交互关系) --- ## 2. 接口规则 ### 2.1 协议规则 **基本规范**: - 通信协议:HTTP/HTTPS - 字符编码:UTF-8 - 请求格式:application/x-www-form-urlencoded 或 application/json - 响应格式:JSON **域名地址**: - 正式环境:http://api.hahabianli.com - 测试环境:(如需测试环境请联系运营人员) ### 2.2 签名规则 **签名说明**: 为保证接口安全,所有接口调用都需要进行签名验证。 **签名算法**: 1. 将所有请求参数按照参数名ASCII码从小到大排序(字典序) 2. 将排序后的参数拼接成字符串:key1=value1&key2=value2&... 3. 在字符串末尾拼接 AppSecret 4. 对拼接后的字符串进行MD5加密,得到签名值 5. 将签名值作为 sign 参数传递 **示例**: ``` 原始参数: access_token=abc123 page_no=1 page_size=20 AppSecret=secret_key 排序后拼接: access_token=abc123&page_no=1&page_size=20&appsecret=secret_key MD5加密后得到 sign 值 ``` ### 2.3 登陆获取 access_token **简要描述**:获取访问令牌,用于后续所有API调用的身份验证。 **请求URL**:`http://api.hahabianli.com/token/get` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |------------|------|------|------| | app_id | 是 | string | Appid, 哈哈便利提 供给商户 | | app_secret | 是 | string | Appsecret,哈哈便利 提供给商户.| | rand_str | 是 | string | 6 位随机数字或小写 字母 | **返回示例**: ```json { "code": 1, "info": "SUCCESS", "data": { "access_token": "169efc8ffe416006910bd606380782148b7587f7", "ticket": "f71b31de9e7b8cefa8bb451bc54f9fab", "exprire": 1516779203 } } ``` **返回参数说明**: | 参数名 | 类型 | 说明 | |--------|------|------| | access_token | string | 登陆令牌,之后接口访问使用. | | ticket | string | 回调时用来做数据验签的. | | expires| int | access_token过期时间的时间戳. | **备注**: - access_token 有效期为15天(1296000秒) - token到期前2天内请求接口会自动生成新的access_token,其它时间请求接口将不会更新token - 建议获取到token后自行保存,发现过期或在token到期前的2天内就对token进行更新 - 更多返回错误代码请看2.4全局错误码 ### 2.4 全局错误码 **通用错误码**: | 错误码 | 说明 | 处理方案 | |--------|------|----------| | 1 | SUCCESS | 操作成功 | | 0 | FAIL | 操作失败 | | -1 | 参数错误 | 检查请求参数是否完整且正确 | | -2 | 签名错误 | 检查签名算法和密钥是否正确 | | -3 | access_token无效 | 重新获取access_token | | -4 | access_token过期 | 重新获取access_token | | -5 | 权限不足 | 联系运营人员开通相应权限 | | -6 | 请求频率超限 | 降低请求频率 | | -7 | 系统繁忙 | 稍后重试 | | -100 | 设备不存在 | 检查设备ID是否正确 | | -101 | 设备离线 | 等待设备上线后重试 | | -102 | 设备故障 | 联系设备维护人员 | | -103 | 设备正在使用中 | 等待当前购物结束后重试 | | -200 | 商品不存在 | 检查商品ID是否正确 | | -300 | 订单不存在 | 检查订单号是否正确 | --- ## 3. 设备接口 ### 3.1 设备列表 **简要描述**:获取商家的设备列表. **请求URL**:`http://api.hahabianli.com/device/getlist` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | 访问 token 如:169efc8ffe416006910bd6063 80782148b7587f7 | | page_no | 是 | int | 第几页,如:1,表示第一页 | | page_size | 是 | string | 每页多少条 ,如:20 表示每页20条数据 | **返回示例**: ```json { "code": 1, "info": "SUCCESS", "data": [ { "id": "xxxxxx", "name": "", "address": "", "status": "1" }, { "id": "xxxxxx", "name": "", "address": "", "status": "1" } ] } ``` **返回参数说明**: | 参数名 | 类型 | 说明 | |--------|------|------| | id | string | 设备 ID | | name | string | 设备名称 | | address | string | 设备地址 | | status | string | 设备状态 (1: 正常, 2: 冻结) | **备注**: - 更多返回错误代码请看首页的错误代码描述 ### 3.2 设备是否多门单开 **简要描述**:查询设备是否为多门单开,如果只有单门柜可忽略此接口; **多门单开定义**: - 设备有多个门,但一次只能开一个; - 多门单开的设备,在调API接口开门时,必须指定门的编号(door_index参数)。从左到右,分别为A门、B门。 **请求URL**:`http://api.hahabianli.com/device/isMultiDoorUnique` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | token | | device_id | 是 | string | 设备编号 | **返回示例**: ```json { "code": 1, "info": "SUCCESS", "data": { "multi_door_unique": 2 } } ``` **返回参数说明**: | 参数名 | 类型 | 说明 | |--------|------|------| | multi_door_unique | int | 是否为多门单开:0-非多门单开,2-双门单开,3-三门单开,4-四门单开 | **备注**: - 目前还没有三门柜、四门柜,值先预留。 - 更多返回错误代码请看首页的错误代码描述 ### 3.3 设备开门 #### 3.3.1 开门 **简要描述**:本接口只是发送开门指令, 是否成功开门, 需要接收消息通知, 来了解设备状态. 接口请求成功后会返回activity_id即活动编号,此编号唯一且每次消费或上货活动都会产生一个与之对应的活动编号,建议商家保存活动编号,方便以后处理售后问题。 **请求URL**:`http://api.hahabianli.com/door/open` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | 访问 token,如:169efc8ffe416006910bd6063 80782148b7587f7 | | device_id | 是 | string | 设备编号 如:D00003 | | out_user_id | 是 | string | 商户系统用户编号(非哈哈系统产生), 商户系统唯一编号 6-32 位数字或字母. | | open_type | 是 | string | 开门类型:IN 表示上货, OUT 表示消费 | | source | 否 | string | 请求来源 | | door_index | 否 | string | 双门标识:A 左门,B 右门, 双门单开柜该参数必传 | **返回示例**: ```json { "code": 1, "info": "success", "data": { "activity_id": "1801081740422435", "user_id": "01081609535A532751AB2DB" } } ``` **返回参数说明**: | 参数名 | 类型 | 说明 | |--------|------|------| | activity_id | string | 选购活动 ID | | user_id | string | 哈哈便利用户 ID | **备注**: - code=1仅表示开门请求成功,是否开门以开关门消息回调结果为准 - 更多返回错误代码请看首页的错误代码描述 #### 3.3.2 开关门结果通知 **简要描述**:在设备开门成功,关门成功或开门失败时会将数据推送到商家后台配置的消息回调地址 **请求方式**:POST **数据说明**: | 参数名 | 必需 | 类型 | 说明 | |--------|------|------|------| | activity_id | 是 | string | 活动编号,如:1712271138560743 | | create_time | 是 | int | 创建时间,如:1633745862 | | device_id | 是 | string | 设备号,如:D00003 | | notify_type | 是 | string | 提醒类型 DEVICE_STATUS:设备状态 | | open_type | 是 | string | IN(补货),OUT(消费) | | out_user_id | 是 | string | 外部用户id | | user_id | 是 | string | 用户id | | status | notify_type==DEVICE_STATUS时 | string | 开门结果:1,ERROR (开门失败)2,OPENED (门已开)3,CLOSED (门已关)4,ANOTHER(设备繁忙,门锁为非关闭状态,请确认关闭后再次扫码) | | sign | 是 | string | 验签,生成规则请查看验签生成规则 | **设备状态返回示例**: ```php Array ( [activity_id] => "1712271138560743", [create_time] => 1633745862, [device_id] => "D00003", [notify_type] => "DEVICE_STATUS", [status] => "OPENED", [open_type] => "OUT", [out_user_id] => "20210918001", [user_id] => "2109181628353272", [sign] => "c9e3b08303408347ae350ab2c8a22a05" ) ``` **返回参数说明**: 确认收到消息通知后,返回 " success " **备注**: - 更多返回错误代码请看首页的错误代码描述 #### 3.3.3 刷卡开门验证 **简要描述**:本接口是由API商家提供给哈哈刷卡开门时调用,接口返回能否开门,当返回可以开门时,哈哈测发起开门指令, 是否成功开门, 需要接收消息通知, 来了解设备状态。 接口请求成功后会返回activity_id即活动编号,此编号唯一且每次消费或上货活动都会产生一个与之对应的活动编号,建议商家保存活动编号,方便以后处理售后问题。 **请求URL**:由API商家提供 **请求方式**:GET **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | cardNo | 是 | string | 卡id | | machineNo | 是 | string | 设备编号 如:B10692 | | timestamp | 否 | string | 请求时间戳(毫秒) | | sign | 否 | string | 请求参数签名 | **返回示例**: ```json { "code": "1000", "status": "success", "data": { "balance": 0 //卡余额 } } ``` **返回参数说明**: | 参数名 | 类型 | 说明 | |--------|------|------| | status | string | 为success时,允许开门 | | data.balance | float | 余额 | **备注**: - status=success 只代表会发送开门指令,是否开门以开关门消息回调结果为准。 - code != 1000 时表示不允许开门,status为不允许开门原因。 - 更多返回错误代码请看首页的错误代码描述 ### 3.4 设备在线状态 #### 3.4.1 设备在线状态 **简要描述**:查询设备的在线和离线状态 **请求URL**:`http://api.hahabianli.com/device/getDeviceOnlineStatus` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | token | | device_id | 是 | string | 设备编号 | **返回示例**: ```json { "code": 1, "info": "SUCCESS", "data": { "device_id": "D00085", "is_online": "0" } } ``` **返回参数说明**: | 参数名 | 类型 | 说明 | |--------|------|------| | is_online | int | 在线状态 0.离线 1.在线 | **备注**: - 更多返回错误代码请看首页的错误代码描述 #### 3.4.2 设备在线状态通知 **简要描述**:该功能需要联系运营人员开通权限,开通后设备在线状态发生变化时,会将在线状态回调至商家后台填写的消息通知地址 **接收方式**:POST **数据说明**: | 参数名 | 类型 | 说明 | |--------|------|------| | device_id | string | 设备编号 | | is_online | int | 设备在线状态 0.不在线 1.在线 | | notify_type | string | 通知类型 ONLINE_STATUS:在线状态 | | signal_val | array | 信息值:表示上线时近两次上报信号值。is_online为0时无此参数 | | ping_val | array | 延时值:表示上线时近两次上报延时值。is_online为0时无此参数 | | sign | string | 签名 | **返回示例**: ```php Array ( [device_id] => "D00085", [is_online]=> "1", [notify_type] => "ONLINE_STATUS", [signal_val] => array:2 [ 0 => array:2 [ "occur_time" => 1573401600 "value" => "1" ] 1 => array:2 [ "occur_time" => 1573401600 "value" => "1" ] ], [ping_val] => array:2 [ 0 => array:2 [ "occur_time" => 1573401600 "value" => "1" ] 1 => array:2 [ "occur_time" => 1573401600 "value" => "1" ] ], [sign] => "c9e3b08303408347ae350ab2c8a22a05" ) ``` **返回参数说明**: 确认收到消息通知后,返回 " success " **备注**: - 更多返回错误代码请看首页的错误代码描述 ### 3.5 设备音量调节 #### 3.5.1 音量调节 **简要描述**: 该接口仅限动态柜(视频识别柜)使用 用于调节动态设备的音量大小; 调用此接口会立即返回结果,只代表指令已推送给设备,不表示已经设置成功; 设备音量是否真正调节成功,需要通过异步通知接口接收结果,请查阅“回调接口”章节的“设备音量调节结果通知”。 **请求URL**:`http://api.hahabianli.com/device/voiceControl` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | token | | device_id | 是 | string | 设备编号 | | voice | 是 | number | 音量大小值 0~15 | **返回示例**: ```json { "code": 1, "info": "SUCCESS" } ``` **备注**: - 返回 code=1 只代表指令已推送给设备,不表示已经设置成功; - 设备音量是否真正调节成功,需要通过异步通知接口接收结果,请查阅“回调接口”章节的“设备音量调节结果通知”; - 更多返回错误代码请看首页的错误代码描述。 #### 3.5.2 设备音量调节结果通知 **简要描述**:设备音量调节成功,哈哈会通过此回调接口告知商户。 **请求方式**:POST **数据说明**: | 参数名 | 必需 | 类型 | 说明 | |--------|------|------|------| | notify_type | 是 | string | 回调类型,此处固定值:VOICE_RESULT | | device_id | 是 | string | 设备号,如:D00003 | | voice | 是 | number | 音量值,为 0~15 的数字 | | sign | 是 | string | 如:eb17ae3ae97600f2b357dc598f86b6c1 | **返回示例**: ```php Array ( [notify_type] => "VOICE_RESULT", [device_id] => "B10692", [voice] => 6, [sign] => "819bb39c0a93c05e485568083a6c8784" ) ``` **返回参数说明**: 确认收到消息通知后,返回 " success " **备注**: - 更多返回错误代码请看首页的错误代码描述 ### 3.6 设备和锁的状态 #### 3.6.1 设备和锁的状态查询 **简要描述**:查询锁状态. **请求URL**:`http://api.hahabianli.com/device/checkstatus` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | 访问 token 如:169efc8ffe416006910bd6063 80782148b7587f7 | | device_id | 是 | string | 设备号,如:D00085 | **返回示例**: ```json { "code": 1, "info": "SUCCESS", "data": { "device_id": "D00085", "status": 1, "device_status": "1" } } ``` **返回参数说明**: | 参数名 | 类型 | 说明 | |--------|------|------| | device_id | string | 设备编号 | | status | int | 1.开 2.关3.无法获取4.异常 | | device_status | string | 1.正常 2.冻结3.学习4.异常 | **备注**: - 更多返回错误代码请看首页的错误代码描述 --- ## 4. 商品接口 ### 4.1 设备可售卖商品列表 **简要描述**:根据设备Id和商品条码获取商品信息。如果只传了设备ID返回该设备对应的商品信息,如果传了设备ID和商品code,返回该设备下商品code对应的商品信息 **请求URL**:`http://api.hahabianli.com/product/getProductsListByDeviceId` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | token | | device_id | 是 | string | 设备Id | | code | 否 | string | 商品code | **返回示例**: ```json { "code": "1000", "info": "success", "data": { "dataInfo": [{ "name": "饮料", "goods": [{ "id": "369", "code": "baishiguan", "type": "饮料", "name": "百事可乐罐330ML", "pic": "https://upload.hahabianli.com/img/201810/21/5bcc24bbd465622185.png", "rec_pic": "/img/201805/21/5b028d48c76f2.png", "c_price": "0.05", "discount": "false", "dis_price": "", "pre_type": "饮料" }] }], "cat": ["饮料"] } } ``` **返回参数说明**: | 参数名 | 类型 | 说明 | |--------|------|------| | name | string | 所属分类名称 | | goods | array | 商品信息 | | goods.id | int | 商品ID | | goods.code | string | 商品code | | goods.type | string | 类目 | | goods.name | string | 完整商品名 | | goods.pic | string | 商品图 | | goods.rec_pic | string | 算法识别图 | | goods.c_price | string | 价格 | | goods.discount | string | 是否折扣 | | goods.dis_price | string | 活动值 | | goods.pre_type | string | 饮料 | | cat | array | 分类 | ### 4.2 商品总库 **简要描述**:获取商品总库的商品 **请求URL**:`http://api.hahabianli.com/product/getAssignedProducts` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | 访问token | | barcode | 否 | string | 条形码,多个条形码用逗号隔(,)开 | | code | 否 | string | 商品code,多个商品code用逗号(,)隔开 | | product_name | 否 | string | 商品名称 | | device_adapt | 否 | string | 适应设备 不传默认为动静态均已学习商品,static:静态已学习商品 dynamic:动态已学习商品 all:动态或静态已学商品 | | page_no | 是 | interger | 当前页 | | page_size | 是 | interger | 每页条数 | **返回示例**: ```json { "code": 1, "info": "SUCCESS", "data": { "total": 99, "data": [{ "code": "naicha", "name": "奶茶", "barcode": "4711162987080", "pic": "https://upload.hahabianli.com/img/201908/02/5d43edcbd7e4882849.png", "planogram": "https://upload.hahabianli.com/img/201908/02/5d43edc5821a591182.png", "static_status": 1, "dynamic_status": 2, "is_open_client":1 }, { "code": "naicha", "name": "奶茶", "barcode": "4711162987080", "pic": "https://upload.hahabianli.com/img/201908/02/5d43edcbd7e4882849.png", "planogram": "https://upload.hahabianli.com/img/201908/02/5d43edc5821a591182.png", "static_status": 1, "dynamic_status": 2, "is_open_client":1 } ] } } ``` **返回参数说明** | 参数名 | 类型 | 说明 | |--------|------|------| | total | interger | 总数量 | | code | string | 商品编码 | | name | string | 商品完整名称 | | barcode | string | 条形码 | | pic | string | 商品图片 | | planogram | string | 商品陈列图 | | static_status | string | 静态柜学习状态: 0.待学习 1.已上架 2.已下架 | | dynamic_status | string | 动态柜学习状态: 0.待学习 1.已上架 2.已下架 3.学习中 | | is_open_client | int | 是否需要开放所有商家,1:是,0:否 | ### 4.3 添加商品至商家商品库 **简要描述**:添加商家商品信息 **请求URL**:`http://api.hahabianli.com/Product/addClientProducts` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | 访问token | | code_list | 是 | string | 商品列表(传入哈哈的商品编码,多个中间用逗号隔开) | **返回示例**: ```json { "code": 1, "info": "success" } ``` ### 4.4 商家商品库 **简要描述**:获取商家的商品列表.. **请求URL**:`http://api.hahabianli.com/product/getClientProducts` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | 访问 token 如:169efc8ffe416006910bd6063 80782148b7587f7 | | page_no | 否 | int | 第几页,如:1,表示第一页 | | page_size | 否 | string | 每页多少条 ,如:20 表示每页20条数据 | | name | 否 | string | 商品名称 | | bar_code | 否 | string | 商品条码 | | apply_status | 否 | string | 适用设备:1全部柜,2静态柜,3动态柜 | | code | 否 | string | 商品编码 | **返回示例**: ```json { "code": 1, "info": "success", "data": { "listData": [ { "product_id": "179", "name": "脉动维生素饮料青柠口味600ml", "pic": "http://upload.hahabianli.com/img/201808/03/5b64197dd779c.jpg", "apply_status": "全部", "cost_price": "0.00", "planogram": "http://upload.hahabianli.com/img/201808/16/5b75009d03fe3.jpg", "customer_id": "", "bar_code": "6902538004045", "type": "饮料", "cprice": "0.03", "code": "maidongqingningwei", "add_time": "2017-11-16 05:29:30" } ], "totals": "1", "page_size": "20", "page_no": "1" } } ``` **返回参数说明** | 参数名 | 类型 | 说明 | |--------|------|------| | totals | num | 商品总条数 | | page_size | num | 每页显示条数 | | page_no | num | 当前页码 | | listData | Object | 商品信息 | | product_id | int | 商品id | | name | string | 商品名称 | | pic | string | 商品图 | | apply_status | string | 适用设备:全部柜,静态柜,动态柜 | | cost_price | string | 商品成本价 | | planogram | string | 商品陈列图 | | customer_id | string | 商家自定义商品id | | bar_code | string | 商品条码 | | type | string | 商品分类 | | cprice | string | 门店统一售价 | | code | string | 商品编码 | | add_time | string | 添加总库时间 | ### 4.5 商品上下架 **简要描述**:商品上下架,给指定设备配置可售卖的商品 **请求URL**:`http://api.hahabianli.com/systemtemplate/deviceGoods` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | 访问token | | device_id | 是 | string | 设备id,sn号 | | goods_code | 是 | string | 商品code,多个商品code用逗号(,)隔开 | | sales_type | 否 | string | 上下架类型:IN上架,OUT下架。call_type=’CHANGE’时必传。 | | call_type | 否 | string | 请求更新方式:CHANGE更新模式,COVER覆盖模式,不传默认值是CHANGE。 | **返回示例**: ```json { "code": 1, "info": "商品操作成功", "data": [ "longfu", "lvcha", "ningfushanquan", "yibao" ] } ``` **返回参数说明** | 参数名 | 类型 | 说明 | |--------|------|------| | data | array | 柜子商品code | #### 4.5.1 获取设备层模板 **简要描述**:获取设备层模板信息 **请求URL**:`http://api.hahabianli.com/product/getLayerTypeInfo` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | 访问token | | device_id | 是 | string | 设备id,sn号 | **返回示例**: ```json { "code": 1, "info": "success", "data": { "id": "2204011048164720",//模板ID "name": "系统层模板_D31452",//模板名称 "type": 4,//设备类型 "shelf_num": "5",//机柜层数 "products": { "left": [//左门 { "floor": "1",//第一层 "goods": [ { "key": "zsnrj",//商品code "label": "芝士牛肉卷",//商品名称 "stock": 0,//库存 "type": "食品",//商品分类 "pic": "https://upload.hahabianli.com/img/202203/24/623c5ebb92b8a1256.jpg",//商品图片 "c_price": "0.02" //商品价格 } ] }, { "floor": "2", "goods": [ { "key": "jinyinhualu", "label": "午时金银花露340ml", "stock": 0, "type": "饮料", "pic": "https://upload.hahabianli.com/img/201811/14/5bebaa90de1ef30408.png", "c_price": "0.02" } ] } ], "right": [ { "floor": "1", "goods": [ { "key": "naicha", "label": "统一阿萨姆奶茶500ml", "stock": 0, "type": "饮料", "pic": "https://upload.hahabianli.com/img/201810/18/5bc81ae86353882913.png", "c_price": "2.00" } ] } ] }, "goods_rule": "" } } ``` #### 4.5.2 创建更新层模板接口 **简要描述**:创建更新设备层模板信息,前提:需要先签署商品互斥协议 **请求URL**:`http://api.hahabianli.com/product/postLayerTypeInfo` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | 访问token | | device_id | 是 | string | 设备id,sn号 | | products | 是 | string | 层模板商品数据(json) | **products参数说明** ```json { "left": [{ "floor": 1,//第一层 "goods": ["zsnrj", "blxml"]//商品编码 }, { "floor": 2, "goods": ["jinyinhualu", "bsklbtwlw8106"] }], "right": [{ "floor": 1,// "goods": ["naicha", "longfu", "leshishupian", "bsklbtwlw8106"] }] } ``` **返回示例**: ```json { "code": 1, "info": "success", "data": { "is_effect": 1 //模板生效 } } ``` ### 4.6 新品申请 #### 4.6.1提交申请 **简要描述**:用于申请商品总库中没有且商家需要在设备中售卖的商品 调用本接口会立即返回结果,仅代表创建工单成功,不表示申请商品成功 申请商品是否成功,需要通过异步通知接口接收结果,请查阅"回调接口"章节的"新品审核结果"。 **请求URL**:`http://api.hahabianli.com/goods/addClientNewGoodsInfo` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | 访问token | | type | 是 | string | 商品类型:0静态,1动态 | | sticker_num | 否 | string | 学习机号 | | name | 是 | string | 商品名称 | | bar_code | 否 | string | 条形码(标品必填) | | specification | 否 | string | 规格 | | columns | 否 | string | 商品占列 | | img_type | 否 | string | 上传图片类型,可传选项:file或者url。不传默认为:file类型 | | pic_1 | 是 | file | 正面图/平面图,img_type=file时,传图片文件(form表单提交multipart/form-data)。img_type=url时,传图片路径,图片上传接口,请查看:图片上传 | | pic_2 | 是 | file | 商品背面图/点位图 img_type=file时,传图片文件(form表单提交multipart/form-data)。img_type=url时,传图片路径,图片上传接口,请查看: 图片上传 | | pic_3 | 是 | file | 商品侧面图/陈列图 img_type=file时,传图片文件(form表单提交multipart/form-data)。img_type=url时,传图片路径,图片上传接口,请查看: 图片上传 | | pic_4 | 是 | file | 商品侧面图/顶部图 img_type=file时,传图片文件(form表单提交multipart/form-data)。img_type=url时,传图片路径,图片上传接口,请查看: 图片上传 | | pic_5 | 是 | file | 商品称重图 img_type=file时,传图片文件(form表单提交multipart/form-data)。img_type=url时,传图片路径,图片上传接口,请查看: 图片上传 | | ori_pic_1 | 是 | file | 正面图原图 img_type=file时,传图片文件(form表单提交multipart/form-data)。img_type=url时,传图片路径,图片上传接口,请查看: 图片上传 | | ori_pic_2 | 是 | file | 背面图原图 img_type=file时,传图片文件(form表单提交multipart/form-data)。img_type=url时,传图片路径,图片上传接口,请查看: 图片上传 | | ori_pic_3 | 是 | file | 侧面图原图 img_type=file时,传图片文件(form表单提交multipart/form-data)。img_type=url时,传图片路径,图片上传接口,请查看: 图片上传 | | ori_pic_4 | 是 | file | 顶部图原图 img_type=file时,传图片文件(form表单提交multipart/form-data)。img_type=url时,传图片路径,图片上传接口,请查看: 图片上传 | | length | 否 | interger | 长度mm | | width | 否 | interger | 宽度mm | | height | 否 | interger | 高度mm | | exhibit_height | 否 | interger | 陈列高度mm | | remark | 否 | interger | 备注 | | standard | 是 | interger | 商品是否标品1标品,2非标品 | | numbers | 否 | interger | 一个货道放几个 | | product_extends | 否 | string | 扩展字段 | | retail_price | 否 | float | 建议零售价 | | cost_price | 否 | float | 成本价 | **返回示例**: ```json { "code": 1, "info": "success", "data": { "id": "20340033577129682091" } } ``` **返回参数说明** | 参数名 | 类型 | 说明 | |--------|------|------| | id | string | 新品申请工单编号 | #### 4.6.2图片上传 **简要描述**:上传图片 **请求URL**:`http://api.hahabianli.com/goods/uploadImg` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | 访问token | | file | 是 | file | 图片文件(form表单提交multipart/form-data) | **返回示例**: ```json { "code": 1, "info": "success", "data": { "img_url": "/img/202112/13/61b6b324db6fa83556.jpg" } } ``` **返回参数说明** | 参数名 | 类型 | 说明 | |--------|------|------| | img_url | string | 图片地址 | #### 4.6.3查看新品申请 **简要描述**:获取新品申请商品信息 **请求URL**:`http://api.hahabianli.com/goods/getNewClientGoodsInfo` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | 访问token | | code | 否 | string | 商品code | | id | 否 | string | 新品申请主键id | **返回示例**: ```json { "code": 1, "info": "success", "data": [ { "id": "20176907376132122061", "type": "1", "client_id": "1807020244131334", "sticker_num": "c0345", "name": "测试", "code": "test0204", "bar_code": "11111", "specification": "", "columns": "", "pic_1": "/img/202104/06/606c005a5d04f4889.jpg", "pic_2": "/img/202104/06/606c0060e246881618.jpg", "pic_3": "/img/202104/06/606c00667441c53484.jpg", "pic_4": "", "length": "0", "width": "0", "height": "0", "exhibit_height": "0", "numbers": "0", "remark": "", "is_general": "0", "status": "1", "phone": "", "retail_price": null, "cost_price": "1.00", "product_type": null, "reject_reason": "", "standard": "2", "operator_uid": "307", "created_at": "2021-04-06 14:32:17", "updated_at": "2021-06-01 15:19:34" } ] } ``` **返回参数说明** | 参数名 | 类型 | 说明 | |--------|------|------| | id | string | 商家商品商品唯一编码 | | type | interger | 商品类型:0静态,1动态 | | client_id | string | 商家ID | | sticker_num | string | 学习机号 | | name | string | 商品名称 | | code | string | 商品编码 | | bar_code | string | 条形码 | | specification | string | 规格 | | columns | string | 商品占列 | | pic_1 | string | 正面图/点位图 | | pic_2 | string | 背面图/平面图 | | pic_3 | string | 侧面图/陈列图 | | pic_4 | string | 顶部图 | | length | interger | 长度mm | | width | interger | 宽度mm | | height | interger | 高度mm | | exhibit_height | interger | 陈列高度mm | | numbers | interger | 一个货道放几个 | | remark | string | 备注 | | is_general | interger | 是否通用:0否,1是 | | status | interger | 审核状态:0审核中,1已通过,2已拒绝,3.已上架 | | phone | string | 手机号 | | retail_price | float | 建议零售价 | | cost_price | float | 成本价 | | product_type | string | 类目,如:水果,饮料等 | | reject_reason | string | 被拒绝原因 | | standard | interger | 商品是否标品1标品,2非标品 | | operator_uid | interger | 审核人id | | created_at | string | 创建时间 | | updated_at | string | 更新时间 | #### 4.6.4新品审核结果回调 **简要描述**:新品审核结果 **请求方式**:POST **数据说明**: | 参数名 | 必需 | 类型 | 说明 | |--------|------|------|------| | status | 是 | interger | 审核状态:1已通过,2已拒绝,3.已上架 | | reject_reason | 是 | string | 被拒绝原因 | | id | 是 | string | 新品申请唯一编码 | | msg | 是 | string | 审核结果信息 | | name | 是 | string | 商品名称 | | bar_code | 是 | string | 条形码 | | code | 是 | string | 商品code标识符,拒绝为空,审核通过不为空 | | notify_type | 是 | int | 消息通知类型(CLIENT_NEW_PRODUCT)新品审核 | | product_extends | 否 | string | 扩展字段信息 | | sign | 是 | string | 验签,生成规则请查看验签生成规则 | **识别结果返回示例** ```php Array ( [bar_code] => "20210913006" [id] => "20315850049321972025" [msg] => 已拒绝 [name] => 哈哈api测试新品申请 [notify_type] => CLIENT_NEW_PRODUCT [reject_reason] => 商品名称不合规范,请参考示例,重新编辑商品名称 [status] => "2" [code] => "" [product_extends] => "1212374" [sign] => fba0b9b78efd190c4858c88afb488c93 ) ``` **返回参数说明** 确认收到消息通知后,返回 " success " ### 4.7 商品编号对应关系 #### 4.7.1获取商品编号对应关系 **简要描述**:获取哈哈商品编号与商家自定义商品编号对应关系, 需联系运营人员开通自定义编号权限 如果商户有自己的商品库,需要自定义商品信息的话,可以考虑对接此接口。 **请求URL**:`http://api.hahabianli.com/product/getProductsRelation` **请求方式**:POST **请求参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | token | | code_list | 否 | string | 哈哈商品编号列表,多个用逗号隔开 | **返回示例**: ```json { "code": 1, "info": "SUCCESS", "data":{ "lvhezhuang": "lvhezhuang01", "longfu": "longfu01" } } ``` **返回参数说明** | 参数名 | 类型 | 说明 | |--------|------|------| | data | json | key为哈哈商品编号,value为商家自定义编号 | ### 4.8 商品合并 #### 商品合并结果通知 **触发条件**:商品合并操作完成时推送 **参数说明**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | notify_type | 是 | string | 固定值:**MERGE_PRODUCT** | | list | 是 | array | 商品合并列表 | | sign | 是 | string | 签名 | **list 数组元素说明**: - `main_code` (string): 主商品code,正常使用的商品code - `product_code` (string): 合并的相同商品的code,除主商品code外,同组其他商品code将不再使用 **list 示例**: ```json [ { "main_code": "dongpengteyinpingzhuang", "product_code": "dpty8988,dpty6525,dpty500ml" }, { "main_code": "hongshiliubaiputaoguozhi", "product_code": "hongshiliuputao,hongshiliubaiputaoguozhi" } ] ``` **回调示例**: ```json { "list": [ { "main_code": "dongpengteyinpingzhuang", "product_code": "dpty8988,dpty6525,dpty500ml,dongpemg500ml,dongpengteyinpingzhuang" }, { "main_code": "hongshiliubaiputaoguozhi", "product_code": "hongshiliuputao,hongshiliubaiputaoguozhi" } ], "notify_type": "MERGE_PRODUCT", "sign": "fba0b9b78efd190c4858c8xxxxxxxxxx" } ``` **返回要求**: ``` success ``` --- ## 5. 订单接口 ### 5.1 回调通知说明 **回调地址配置**: 在商家后台配置一个消息回调地址,用于接收所有类型的通知: - 开关门状态通知 (DEVICE_STATUS) - 设备在线状态通知 (ONLINE_STATUS) - 设备音量调节结果通知 (VOICE_RESULT) - 新品审核结果回调 (CLIENT_NEW_PRODUCT) - 商品合并结果通知 (MERGE_PRODUCT) - **AI识别结果通知 (ORC_RESULT)** - 最重要 **回调通知特点**: - 所有通知都通过同一个消息回调地址接收 - **必须包含 `notify_type` 字段**用于区分具体的业务类型 - 所有通知都包含 `sign` 字段用于验证 - 商户必须返回 `success` 字符串表示接收成功 - 未正确响应会触发重试机制(最多3次,间隔5秒、30秒、60秒) **notify_type 枚举值**: | notify_type 值 | 说明 | |-------------------|------| | DEVICE_STATUS | 开关门状态通知 | | ONLINE_STATUS | 设备在线状态通知 | | VOICE_RESULT | 音量调节结果通知 | | CLIENT_NEW_PRODUCT | 新品审核结果回调 | | MERGE_PRODUCT | 商品合并结果通知 | | ORC_RESULT | AI识别结果通知 | **签名验证**: - 将所有参数(除sign外)按字典序排序 - 拼接成 key1=value1&key2=value2 格式 - 末尾拼接 AppSecret - 进行MD5加密得到签名值 **幂等性要求**: - 商户需要实现幂等性处理,避免重复通知导致重复业务处理 - 建议通过 activity_id 或 device_id + create_time 进行幂等性校验 **重要提示**: - **ORC_RESULT(识别结果通知)是最重要的回调**,包含用户购买的商品信息 - 商户应根据识别结果进行扣款操作 - 当 nobuy=1 时表示用户没有消费,不需要扣款 - 当识别结果中 excepts 包含值时,建议人工审核 ### 5.2 识别或订单回调结果查询 **简要描述**: 回调信息查询 **请求URL**: http://api.hahabianli.com/order/getCallbackInfo **请求方式**: POST **参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | type | 是 | string | 识别类型: REC识别结果回调,ORDER 订单结果回调 | | act_id | 是 | string | 活动编号 | | access_token | 是 | string | token | **返回示例**: **type==REC返回结果**: ```json { "code": 1, "info": "success", "data": { "activity_id": "1911041443149709", "create_time": 1572849846, "device_id": "D00527", "nobuy": 0, "notify_type": "ORC_RESULT", "out_user_id": "77094", "result": "{\"type\":\"OUT\",\"data\":{\"yundongyinliaochengmiweijianlibaoping\":\"-1\",\"weitaninmengcha\":\"-2\"}}", "sku_list": "[{\"sku\":\"1459\",\"number\":\"-1\",\"code\":\"yundongyinliaochengmiweijianlibaoping\",\"index\":1},{\"sku\":\"26\",\"number\":\"-2\",\"code\":\"weitaninmengcha\",\"index\":2}]", "source": "fe", "user_id": "1907131419287902", "sign": "103b51610978b99ba893053c7ba2272e" } } ``` **type==ORDER返回结果**: ```json { "code": 1, "info": "success", "data": { "order_id": "1911041457190775", "device_id": "D00749", "activity_id": "1172850261253081857", "user_id": "1272523247122359678", "order_name": "Hamu牌红番石榴汁(红芭乐汁)饮料瓶装490ml x 1", "order_detail": "{\"Hamuhongfanshiliuzhi\":\"-1\"}", "from": "WECHAT", "order_money": "0.10", "create_time": 1572850639 } } ``` **返回参数说明**: | 参数名 | 类型 | 说明 | |--------|------|------| | code | int | 状态码:1正常 | | info | string | 提示信息 | | data | json | 回调查询数据结果集 | ### 5.4 识别结果查询 **简要描述**: 查询订单的识别结果 **请求URL**: http://api.hahabianli.com/order/recResult **请求方式**: POST **参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | order_id | 与activity_id其中一项必选 | string | 订单编号 | | activity_id | 与order_id其中一项必选 | string | 活动编号 | | access_token | 是 | string | token | **返回示例**: ```json { "code": 1, "info": "SUCCESS", "data": { "result": { "kangshifuqingyangguo": -1 "nongfushanquan": -2 }, "sku_result": [ { "productId": "s1993432", "count": -1 }, { "productId": "s3252522", "count": -2 } ] } } ``` **返回参数说明**: | 参数名 | 类型 | 说明 | |--------|------|------| | result | json | 哈哈商品编码的识别结果。key:商品编码,value:商品数量(整型) | | sku_result | json | 自定义商品编码的识别结果。数组,productId: 自定义商品编码,count: 商品数量(整型) | ### 5.5 订单查询 **简要描述**: 用于查询订单的详细信息 **请求URL**: http://api.hahabianli.com/order/getOrderInfo **请求方式**: POST **参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | order_id | 与activity_id其中一项必填 | string | 订单号 | | activity_id | 与order_id其中一项必填 | string | 活动号(开门后得到的流水号) | | access_token | 是 | string | token | **返回示例**: ```json { "code":1, "info":"SUCCESS", "data":{ "order_id":"1811132102372060", "device_id":"C0740", "activity_id":"1142114077170142896", "user_id":"05081436135AF1455D38909", "out_user_id":"100001XXX" "order_name":"墨西哥原装进口科罗娜特级啤酒330ml x 1", "order_detail":"{\"keluonaipijiu\":\"-1\"}", "from":"WECHAT", "order_money":"0.10", "create_time":"1542114157" } } ``` **返回参数说明**: | 参数名 | 类型 | 说明 | |--------|------|------| | order_id | string | 订单编号 | | device_id | string | 设备编号 | | activity_id | string | 活动编号 | | user_id | string | 用户编号(哈哈系统编号) | | out_user_id | string | 用户编号(商家系统编号) | | order_name | string | 订单标题 | | order_detail | string | 订单明细 | | from | string | 来源 如:API | | order_money | decimal | 订单金额 | | create_time | int | 创建时间 | ### 5.6 设置订单支付状态 **简要描述**: 用于更新订单支付状态,标记订单、活动状态为已支付 **请求URL**: http://api.hahabianli.com/order/setOrderStatus **请求方式**: POST **参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | order_id | 必填 | string | 订单号 | | access_token | 是 | string | token | **返回示例**: ```json { "code":1, "info":"SUCCESS", "data":"" } ``` ### 5.7 开门前后图片或视频查询 **简要描述**: 获取商家提交售后的订单开门前和开门后的图片或视频. **请求URL**: http://api.hahabianli.com/order/getorderspic **请求方式**: POST **参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | access_token | 是 | string | 访问 token 如:169efc8ffe416006910bd6063 80782148b7587f7 | | order_id | 否 | string | 订单号,与活动编号选其一,如:1803241109010077 | | activity_id | 否 | string | 活动编号,与订单编号选其一,如:1164168368391141447 | **返回示例**: **静态事例**: ```json { "code": 1, "info": "SUCCESS", "data": { "device_type":0 "begin_image": [ "http://XXXXX/XXX/xXX.jpg", "http://XXXXX/XXX/xXX.jpg" ], "end_image": [ "http://XXXXX/XXX/xXX.jpg", "http://XXXXX/XXX/xXX.jpg" ] } } ``` **动态事例**: ```json { "code": 1, "info": "SUCCESS", "data": { "device_type": "1", "video_url":"http://XXXXX.mp4", "main_video": [//主视频 "http://xxxxx.mp4" ], "subsidiary_video": [//辅助视频 "http://xxxxx.mp4" ] } } ``` **返回参数说明**: | 参数名 | 类型 | 说明 | |--------|------|------| | device_type | string | 设备类型 0.静态 1.动态 | | begin_image | string | 开门前图片 | | end_image | string | 关门后图片 | | video_url | string | 视频地址 | ### 5.8 静态柜分层图片与识别结果 **简要描述**: 查询每一层的图片与识别结果(仅限静态柜) **请求URL**: http://api.hahabianli.com/order/recResultLayers **请求方式**: POST **参数**: | 参数名 | 必选 | 类型 | 说明 | |--------|------|------|------| | order_id | 与activity_id其中一项必选 | string | 订单编号 | | activity_id | 与order_id其中一项必选 | string | 活动编号 | | access_token | 是 | string | token | **返回示例**: ```json { "code": 1, "info": "SUCCESS", "data": [ { "begin_image": "http://img.hahabianli.com/buy/201908/05/5d47cc7c3783a71347.jpg", "end_image": "http://img.hahabianli.com/buy/201908/05/5d47cc883b63d84520.jpg", "result": [], "sku_result": [] }, { "begin_image": "http://img.hahabianli.com/buy/201908/05/5d47cc7c374e486861.jpg", "end_image": "http://img.hahabianli.com/buy/201908/05/5d47cc883b2c473523.jpg", "result": [], "sku_result": [] }, { "begin_image": "http://img.hahabianli.com/buy/201908/05/5d47cc7c3768943153.jpg", "end_image": "http://img.hahabianli.com/buy/201908/05/5d47cc883b4524252.jpg", "result": { "xiaomingtongxueliuli": -1 }, "sku_result": [ { "productId": "xiaoming", "count": -1 } ] }, { "begin_image": "http://img.hahabianli.com/buy/201908/05/5d47cc7c379d533815.jpg", "end_image": "http://img.hahabianli.com/buy/201908/05/5d47cc883b10764949.jpg", "result": { "kangshifuqingyangguo": -1 "nongfushanquan": -2 }, "sku_result": [ { "productId": "s1993432", "count": -1 }, { "productId": "s3252522", "count": -2 } ] } ] } ``` **返回参数说明**: | 参数名 | 类型 | 说明 | |--------|------|------| | begin_image | string | 开门前图片 | | end_image | string | 关门后图片 | | result | json | 哈哈商品编码的识别结果。key:商品编码,value:商品数量(整型) | | sku_result | json | 自定义商品编码的识别结果。数组,productId: 自定义商品编码,count: 商品数量(整型) | --- ## 附录 ### A. 完整接口清单 #### 1. 接口规则(4个) - 2.1 协议规则 - 2.2 签名规则 - 2.3 登陆获取 access_token - 2.4 全局错误码 #### 2. 设备接口(9个) - 3.1 设备列表 - 3.2 设备是否多门单开 - 3.3.1 开门 - 3.3.2 开关门结果通知 - 3.3.3 刷卡开门验证 - 3.4 设备在线状态 - 3.5 设备音量调节 - 3.6 设备和锁的状态 #### 3. 商品接口(10个) - 4.1 设备可售卖商品列表 - 4.2 商品总库 - 4.3 添加商品至商家商品库 - 4.4 商家商品库 - 4.5 商品上下架 - 4.5.1 获取设备层模板 - 4.5.2 创建更新层模板接口 - 4.6 新品申请 - 4.7 商品编号对应关系 - 4.8 商品合并 #### 4. 订单接口(8个) - 5.1 识别结果通知 - 5.2 订单信息通知 - 5.3 识别或订单回调结果查询 - 5.4 识别结果查询 - 5.5 订单查询 - 5.6 设置订单支付状态 - 5.7 开门前后图片或视频查询 - 5.8 静态柜分层图片与识别结果 ### B. 常见问题 **Q1: access_token多久过期?** A: access_token有效期为15天(1296000秒)。token到期前2天内请求接口会自动生成新的access_token,其它时间请求接口将不会更新token。建议获取到token后自行保存,发现过期或在token到期前的2天内就对token进行更新。 **Q2: 如何处理识别结果通知?** A: 商户应在收到识别结果通知后,根据商品列表和金额进行用户扣款,并调用"设置订单支付状态"接口告知哈哈平台支付结果。 **Q3: 识别置信度低于0.8怎么办?** A: 建议进行人工审核,可通过"开门前后图片或视频查询"接口获取购物视频进行核实。 **Q4: 回调接口没有收到通知?** A: 可通过"识别或订单回调结果查询"接口查询推送状态。如果推送失败,可主动调用"识别结果查询"接口获取数据。 **Q5: 多门柜如何开门?** A: 先调用"设备是否多门单开"接口判断设备类型,如果是多门单开设备,在调用开门接口时需传递door_index参数指定门编号。 --- ## 版本历史 | 版本 | 日期 | 变更内容 | |------|------|----------| | 1.0.0 | 2024-01-24 | 初始版本,包含完整API文档 | --- **文档来源**:https://showdoc.hahabianli.com/web/#/685869388/275897889 **最后更新**:2024-01-24