收款机具 API 接入流程

最近更新时间:2019-10-30 16:42:49

1. 修订记录

版本号 变更内容 变更日期
1.0 创建文档 2019-10-06

2. 概述

机具通过小程序绑定指定商户与门店后,便可收款。机具的绑定和收款功能的后台能力由云支付提供。本文档主要说明了机具厂商如何通过云支付提供的 API,完成云支付后台的接入。

3. 机具要求

显示器能清晰展示 URL 为200字节大小的二维码。

4. 关键名词说明

4.1 sn 前缀

为了确保每个厂商机具的 sn 在云支付系统中不冲突,云支付会给每个厂商分配不同的 sn 前缀。

假设厂商按自有规则生成的原始 sn 为 91RA00001,云支付给厂商分配的 sn 前缀为 BF_M100_BF,其中 BF 为厂商简码,M100为产品型号简码,则需要存在两套新的 sn。

  • 第一套为 BF91RA00001,即在原始 sn 前增加 BF。
  • 第二套(完整 sn)为 BF_M100_BF91RA00001,即在原始 sn 前增加 BF_M100_BF。

调用云支付后台所有接口都使用第二套 sn。其它情况,如机具外壳上贴的 sn 都使用第一套 sn。

4.2 初始密钥

厂商需要给每台机具生成一个初始密钥,密钥是由数字(0-9)和大写字母(A-Z)组成的32字节随机字符串,而且必须是一机一密,不能相同。

调用云支付后台绑定相关接口需要使用这个密钥,详见 机具绑定相关流程说明

此密钥要求高度保密,建议写入机具的安全区,至少要加密后再烧录到磁盘。由于初始密钥由厂商生成,厂商需要尽力保证密钥不外泄。

4.3 交易密钥

机具绑定成功后,会从云支付后台接口中获取到一个交易密钥。调用云支付后台支付相关接口需要使用这个密钥,详见 机具收款相关流程说明

此密钥要求高度保密,获取到交易密钥后,必须先加密再写入磁盘,以防攻击者获取到这个交易密钥。

5. 接入准备工作

5.1 申请初始资源

厂商在正式进入开发阶段时,需要向云支付以邮箱(邮箱地址请咨询负责与厂商对接的人员)的方式申请获取以下内容。

名称 说明
sn 前缀 参见 4.1 sn 前缀
app_cpay_version 由云支付统一规划的机具程序版本号,绑定和数据上报时会用到。
sub_terminal_type 由云支付统一规划的设备类型码,支付的时候会用到。
加密用的公钥文件 public.key 由云支付统一发放的公钥文件,用于 sn 和初始密钥录入,6.2 录入操作说明 会用到。
接收加密文件的邮箱地址 云支付接收 sn 和初始密钥信息的邮箱地址。

5.2 申请测试账号

默认情况下,厂商直接参考接口说明,在正式环境上调试接口即可。如遇后台接口还未正式发布等特殊情况,需要在测试环境调试接口,则联系负责与厂商对接的人员。

  1. sn 和初始密钥。sn 和初始密钥是绑定等流程中必须要的内容。如果在正式环境上调试,则需按第6章所述方法录入 sn 和初始密钥。
  2. 测试商户。如果是正式环境测试,则调试人员需要有微信商业版的商户,通过“收款设备”小程序来完成绑定。

6. 机具出厂准备工作

6.1 背景说明

每台机具的 sn 和初始密钥录入到云支付后台后才能绑定成功,然后才能用于收款,初始密钥说明详见 4.2 初始密钥

每批机具在出厂前,厂商需要把所有 sn 和初始密钥写入到一个文件中,并使用指定方法加密。通过厂商官方邮箱把加密文件发送给云支付指定邮箱,云支付收到邮件后会执行录入操作。录入完成后,云支付会回复邮件提示录入完成,厂商收到录入成功的邮件回复后,这批机具才能正式出厂。

厂商如果想调试绑定相关接口,需要先通这个方式把调试用到的 sn 和初始密钥录入云支付后台。

6.2 录入操作说明

  1. 确认 openssl 版本
    要求版本为 OpenSSL 1.1.0g 2 Nov 2017 及以上,可以通过 openssl version 命令查看版本号。
  2. 生成 sn 和初始密钥文件
    文件只包含两列,第一列为 sn(带完整前缀),第二列为初始密钥,中间以空格分隔,每行结尾不要有多余的空格或其它无关字符,中间不要有空行,最后一行不能为空行。生成的文件名为sn_init_key.txt,文件内容示例如下:
    BF_M100_BF91RA00001 696FF05FA7CE76664211A47CD788CC30
    BF_M100_BF91RA00002 654502BB0F57EC8737B4CF12117575B8
  3. 生成密码文件
    随机生成一个32字节的密码字符串,并把这个密码字符串写入到一个名为encrypt_key.txt的文件。此文件只有一行,不能有多余的空格或空行。每次都要随机生成,不能使用相同的密码字符串。
  4. 加密 sn 和初始密钥文件
    使用第3步生成的encrypt_key.txt文件来加密第2步生成的sn_init_key.txt文件。执行命令:
    openssl aes-128-cbc -salt -in sn_init_key.txt -out sn_init_key.txt.encrypted
    这里会要求输入两次密码,密码内容即为第3步生成文件中的内容,直接从文件中复制过来就行,两次密码输入必须相同。执行成功后会生成一个 sn 和初始化密钥的加密文件sn_init_key.txt.encrypted,即sn_init_key.txt加密后的文件。
  5. 加密密码文件
    使用 5.1 申请初始资源 所述云支付提供的公钥文件public.key加密第三步生成的密码文件encrypt_key.txt。执行命令:
    openssl rsautl -encrypt -inkey public.key -pubin -in encrypt_key.txt -out encrypt_key.txt.encrypted
    执行成功后会生成一个密码文件的加密文件encrypt_key.txt.encrypted
  6. 邮件发送加密文件
    将加密文件发送到 5.1 申请初始资源 所述的接收加密文件的邮箱地址, 需要发送的文件有sn_init_key.txt.encryptedencrypt_key.txt.encrypted。如果要将文件打包进行发送,则必须使用 zip 来压缩。邮件发送时,抄送人需添加厂商相关管理人员。
  7. 其它说明
    以上所有文件都以 UTF-8 编码,发送前请先确认不能有可见/不可见的特殊字符。
    邮件发送完成后,销毁encrypt_key.txtsn_init_key.txt(无用时销毁)文件,同时需保管好public.key文件,这些文件禁止外泄。

7. 机具绑定相关流程说明

7.1 背景说明

商户拿到机具后,需要先操作绑定才能进行收款。机具绑定主要是为了获取支付接口必须的部分参数内容,并在云支付后台建立逻辑绑定关系,从而成功发起收款。

7.2 机具开机或重启

以下为机具开机或重启成功后需要增加的逻辑处理过程:

开机或重启完成后,调用云支付后台 ping 接口获取系统时间,并用获取到的时间修正系统时间。

  • 如果机具系统内的绑定信息为空(没有绑定或恢复了出厂设置),则提示用户去绑定。
  • 如果机具系统内的绑定信息不为空,则通过云支付后check_bill_device_bind_info接口来校验绑定信息是否可用,如果接口返回失败,则展示接口返回的错误信息。check_bill_device_bind_info接口主要完成以下内容,这三件事如果检查通过,则可确保机具能正常收款。
    • 检查机具 sn 对应设备在云支付后台是否是“已绑定”状态;
    • 检查机具的在云支付后台的逻辑绑定关系是否正确;
    • 检查机具支付密钥是否和云支付后台保存的支付密钥一致。
  • 显示屏展示对应提示后,用户可通过按键或其它方式关闭提示信息进行其它操作。

流程中涉及到的接口,详见 接口说明

7.3 绑定

  1. 时序图

    机具增加“生成绑定二维码”的功能项,用户进入这个功能项后,执行时序图中的逻辑。

  2. 获取绑定二维码信息
    机具首先从云支付后台同步一次系统时间。然后通过generate_bill_device_bind_qr_code获取绑定二维码相关信息。generate_bill_device_bind_qr_code接口成功应答后,可以取到5个绑定逻辑相关字段:activator、token、ttl、mini_program_url、interval,接口详细说明详见 接口说明

  3. 生成二维码
    二维码内容组成:mini_program_url?ac=activator&rs=nonce_str&sign=sha256sum&sn=sn

    • mini_program_url 和 activator 来源于generate_bill_device_bind_qr_code接口应答。
    • nonce_str 由机具生成的8字节随机字符串。
    • sign 由机具使用初始密钥和多个字段拼接字符串(拼接格式:ac=activator&rs=nonce_str&sn=sn)计算的 sha256 值,即:hmac_sha256(ac=activator&rs=nonce_str&sn=sn,机具初始密钥)。

    举例说明,假设:

    • mini_program_url 值为:https://payapp.weixin.qq.com/smartqr/entry/home
    • activator 值为:p9fa01zex4mi
    • 机具完整 sn 值为:LANDI_QM600_LA190000000
    • 机具初始密钥值为:C852274D372982D5530B692FD77124D3

    则二维码生成流程为:

    1. 机具生成的8字节随机字符串(nonce_str):c44f32e0
    2. 机具拼接字符串 ac=p9fa01zex4mi&rs=c44f32e0&sn=LANDI_QM600_LA190000000。
    3. 机具计算 sha256:hmac-sha256(“ac=p9fa01zex4mi&rs=c44f32e0&sn=LANDI_QM600_LA190000000”, “C852274D372982D5530B692FD77124D3”) ,获得 HMAC-SHA256 结果:E0CA8FDA56464BDF702FCA1AE9692EB99483E065879247763B3A46B576EBF5AC
    4. 拼接二维码 URL:https://payapp.weixin.qq.com/smartqr/entry/home?ac=p9fa01zex4mi&rs=c44f32e0&sn=LANDI_QM600_LA190000000&sign=E0CA8FDA56464BDF702FCA1AE9692EB99483E065879247763B3A46B576EBF5AC,机具显示器把拼接二维码 URL 展示成二维码。
  4. 轮询绑定结果
    机具展示出绑定二维码后,立即开始定时轮询云支付后台绑定结果。

    • 轮询接口:get_bill_device_bind_info,详见 接口说明
    • 轮询时间间隔:由generate_bill_device_bind_qr_code接口返回的 interval 指定,单位为秒。假设 interval 为1,则机具每次调用get_bill_device_bind_info接口完成后等待1秒再继续调用。
    • 轮询结束条件有两个:
      1. get_bill_device_bind_info接口返回了绑定信息,即应答中 activated为true;
      2. 轮询超过了二维码有效期,有效期长度由generate_bill_device_bind_qr_code接口应答中的 ttl 指定,单位为秒,假如 ttl 为180,表示整个轮询过程超过180秒就必须结束,并停止展示二维码。
  5. 处理绑定信息
    获取到绑定信息后(即 activated 为 true),把应答中的 e_authen_key 内容先做 base64 解码,再执行解密(解密说明详见 10.1 AES-128-CBC 解密说明),解密密钥为机具初始密钥。解密成功后,把解密后的内容和其它绑定信息使用机具自有加密方式加密一次,最后写入磁盘。

8. 机具收款相关流程说明

8.1 支付


刷卡支付接口:https://pay.qcloud.com/cpay/brief_micro_pay,详见 9.6 刷卡支付
查询订单接口:https://pay.qcloud.com/cpay/brief_query_order,详见 9.7 查询支付单

  • 支付方式:微信支付、支付宝支付(配置方法详见 支付宝子商户配置)、会员卡支付,云支付后台通过顾客付款码区分顾客的支付方式。
  • 支付未知:网络请求超时和业务上的结果未知,详见 9.11 其它消息体说明 中 Status 的说明。
  • 接口返回 status 为0,只表示业务请求成功。订单的支付结果需通过订单的状态(即应答中的 cts 字段)来判断。
  • 每次接口调用成功后等待2秒再查单,如果2分钟内查询不到结果,请到手机端管理系统查看交易明细确认支付结果。
  • 支付流程完成后需要上报支付相关信息,详见 9.10 支付信息上报

8.2 退款


退款接口:https://pay.qcloud.com/cpay/refund,详见 9.8 退款
查询退款订单接口:https://pay.qcloud.com/cpay/query_refund_order,详见 9.9 查询退款单

  • 申请退款成功,并不代表退款成功。
  • 退款是一个异步过程,申请退款成功后,只是代表第三方支付平台受理这笔退款,是否到账需要看这笔钱退到哪里。
    • 如果是退款至微信零钱账户或支付宝账户,会很快到账。
    • 如果是退款至顾客的银行卡,到账时间与银行处理进度相关,可能要花几个小时。
  • 申请退款成功后,需告知顾客,申请退款已经成功,请关注后续到账情况。顾客可关注微信或支付宝消息通知,收到已经发起退款或退款到账的消息。
  • 如果想在设备上看这笔退款是否到账,可以调用退款查询接口,通过退款单的状态来查看是否退款成功。适配者可以自己选择是否适配退款查询接口。

8.3 机具支付使用 HTTPS 长连接

  1. 背景
    机具与云支付后台使用 HTTPS 方式交互,如果机具收款时每次都新建连接请求云支付后台,则完成 TCP 握手和 TLS 握手需要很多次网络报文交互,会增加支付相关接口调用的整体耗时,影响收款体验。因此机具需要与云支付后台保持一个 HTTPS 长连接,使用长连接完成支付相关接口调用。

  2. 创建连接

    • 如果机具已绑定,机具启动完成后立即尝试创建与云支付后台的 HTTPS 连接,并保持这个连接,供后续支付使用。如果创建连接过程超时,则跳过此步骤,让机具完成启动。
    • 如果机具未绑定,待机具绑定成功后,立即尝试创建与云支付后台的 HTTPS 连接,并保持这个连接,供后续支付使用。
  3. 保持连接
    每个 HTTPS 请求头设置connection: keep-alive

    每隔2分钟,进行一次真实的 HTTPS 交互,发送请求:GET / HTTP/1.1\r\nHost: pay.qcloud.com\r\nConnection: keep-alive\r\n\r\n,接收完服务器应答后丢掉不处理。

  4. 预热连接
    商家输入完金额并按下确定键之后,每隔0.5秒通过长连接以 GET 方式向后台发送'\r\n' 2个字符,扫码后停止发送,走正常支付流程。GET 请求不会触发后台返回应答。

    伪代码详细说明如下:

    function uplink_warm_up() {
       while true {
          if qrcode_is_ready {
             return
          }
          t = now_time()
    
          https_send('\r\n', 2)
          wait_ack() // 不同机具可能做法不同
          while now_time() - t < 500ms {
             sleep(50ms)
          }
       }
    }

9. 接口说明

9.1 接口规范

摘要 详细说明
传输方式 HTTPS
提交方式 POST
字符编码 UTF-8
内容格式 content_type:application/json
证书校验 严格校验服务端证书。
应答校验 如果应答设置了 authen_info(或 a)则严格校验 authen_code(或 a)的值。

9.2 获取云支付后台系统时间

接口地址

https://pay.qcloud.com/cpay/ping

请求参数

POST 空字符串即可,后台不校验 POST 内容。

应答参数

参数名 必填 类型 长度(Byte) 说明
timestamp Int 8 后台系统的 UNIX 时间戳,单位为秒,如1568810504。
status Int 4 错误码。
description String 最长128 status 对应的错误信息。

示例说明

curl -H "Content-Type:application/json" -X POST -data '' <https://pay.qcloud.com/cpay/ping>

{"description":"ok","status":0,"timestamp":1568810077}

9.3 检查机具绑定信息

接口地址

https://pay.qcloud.com/cpay/check_bill_device_bind_info

请求参数

参数名 必填 类型 长度 说明
request_content String - 请求内容,该 string 可以转为 json 结构,json 格式见本节 RequestContent。
authen_info AuthenInfo - 认证信息,详见“初始密钥认证信息”。

RequestContent 结构

参数名 必填 类型 长度(Byte) 说明
sn_code String - 机具自身的 sn,注意要是完整的 sn,如LANDI_QM800_LA19**********POPSECU_SL51_BP51********
out_shop_id String - 云支付系统内的全局门店 ID,机具绑定成功后即可获得这个 ID。
device_id String - 云支付系统内的逻辑设备 ID,机具绑定成功后即可获得这个 ID。
nonce_str String 8 随机字符串,ASCII 字符(0-9、a-z、A-Z)。
hash_content String 64 authen_key(支付密钥)和随机字符串一起计算的 HAMC-SHA256 的值,authen_key 是在机具绑定成功后解密 e_authen_key 字段获得。
timestamp Int 8 机具系统当前时间,UNIX 时间戳,单位为秒,如1568810504。

应答参数

参数名 必填 类型 长度(Byte) 说明
response_content ResponseContent - 应答内容,详见本节 ResponseContent。
authen_info AuthenInfo - 认证信息,详见“初始密钥认证信息”。

ResponseContent 结构

参数名 必填 类型 长度(Byte) 说明
status Int 4 错误码。
description String 最长128 错误信息。
log_id Int 4 消息 ID。
internal_status Int 4 具体说明见 internal_status 错误码表。

示例说明

请求生成示例代码:

std::string nonce_str = "ea90ceba"    // 生成8字节随机字符串
std::string authen_key_hash = hmac_sha256(authen_key, nonce_str); // 计算 authen_key 的 hash 值

Json::Value request_content;
request_content["sn_code"] = "aaa";
request_content["out_shop_id"] = "ddd";
request_content["device_id"] = "fff";
request_content["nonce_str"] = nonce_str;
request_content["hash_content"] = authen_key_hash;
request_content["timestamp"] = 1568859333;    //当前系统时间

Json::FastWriter w;
std::string request_content_str = w.write(request_content);
std::string authen_code = hmac_sha256(init_key, request_content_str); // 使用机具初始密钥计算签名

Json::Value authen;
authen["authen_code"] = authen_code
authen["authen_type"] = 1; //hmac_sha256 为 1

Json::Value authen_info;
authen_info["a"] = authen; //认证码

Json::Value request; //构造最终发给服务器的请求
request["request_content"] = request_content_str;
request["authen_info"] = authen_info;

std::string request_str = w.write(request);

request_str 即为 post 内容。

请求内容示例:

{
    "authen_info":{
        "a":{
            "authen_code":"091745D976208923097F66771324CA7C6EC32A55ABECAD6C3D42826AA363CA86",
            "authen_type":1
        }
    },
    "request_content":"{
        "device_id":"fff",
        "hash_content":"2F09EFCB064D4F9A4A0BABD5260842D8AC4D0611F4B941A03A77E5E55B5168D7",
        "nonce_str":"ea90ceba",
        "out_shop_id":"ddd",
        "sn_code":"aaa",
        "timestamp":1568859333
    }"
}

应答内容示例:

{
    "response_content":"{
    "status":0,
    "description":"",
    "log_id":18654852,
    "internal_status":0,
    }",
    "authen_info":{
        "a":{
            "authen_type":1,
            "authen_code":"xxxx"
        }
    }
}

9.4. 获取绑定二维码相关信息

接口地址

https://pay.qcloud.com/cpay/generate_bill_device_bind_qr_code

请求参数

参数名 必填 类型 长度 说明
request_content String - 请求内容,该 string 可以转为 json 结构,json 格式见本节 RequestContent。
authen_info AuthenInfo - 认证信息,详见“初始密钥认证信息”。

RequestContent 结构

参数名 必填 类型 长度(Byte) 说明
sn_code String - 机具自身的 sn,注意要是完整的 sn,如LANDI_QM800_LA19**********POPSECU_SL51_BP51********
mcc String - 基站信息中的 mcc 字段,如果未获取到可以不填。
mnc String - 基站信息中的 mnc 字段,如果未获取到可以不填。
lac String - 基站信息中的 lac 字段,如果未获取到可以不填。
cellid String - 基站信息中的 cellid 字段,如果未获取到可以不填。
rss String - 基站信息中的 rss 字段,如果未获取到可以不填。
app_cpay_version String - 由云支付指定的版本号,初始值为1.0.0,需要编译到机具代码中,每次机具升级程序需要向云支付申请一个 app_cpay_version。
nonce_str String 8 随机字符串,ASCII 字符(0-9、a-z、A-Z)。
timestamp Int 8 机具系统当前时间,UNIX 时间戳,单位为秒,如1568810504。

应答参数

参数名 必填 类型 长度(Byte) 说明
response_content ResponseContent - 应答内容,详见本节 ResponseContent。
authen_info AuthenInfo - 认证信息,详见“初始密钥认证信息”。

ResponseContent 结构

参数名 必填 类型 长度(Byte) 说明
status Int 4 错误码。
description String 最长128 错误信息。
log_id Int 4 消息 ID。
internal_status Int 4 具体说明见 internal_status 错误码表。
generate_bill_device_bind_qr_code_response String - 只有 status 为0的时候才存在,具体见 GenerateBillDeviceBindQrCodeResponse 说明。

GenerateBillDeviceBindQrCodeResponse

参数名 必填 类型 长度(Byte) 说明
activator String 12 二维码唯一标识,用于生成绑定二维码。
token String 12 轮询绑定结果时要用到的票据。
ttl Int 4 二维码有效时间,单位为秒,如180,表示二维码3分钟内有效。
mini_program_url Int 4 收款设备小程序的 url,用于生成绑定二维码。
interval Int 4 轮询绑定结果的时间间隔,单位为秒。

示例说明

请求生成示例代码:

Json::Value request_content;
request_content["sn_code"] = "aaa";
request_content["mcc"] = "bbb";
request_content["mnc"] = "ccc";
request_content["lac"] = "ddd";
request_content["cellid"] = "eee";
request_content["rss"] = "fff";
request_content["app_cpay_version"] = "1.0.0";
request_content["nonce_str"] = "ea90ceba";    // 8字节随机字符串
request_content["timestamp"] = 1568859333;    // 当前系统时间

Json::FastWriter w;
std::string request_content_str = w.write(request_content);
std::string authen_code = hmac_sha256(init_key, request_content_str); // 使用机具初始密钥计算签名

Json::Value authen;
authen["authen_code"] = authen_code;
authen["authen_type"] = 1; //hmac_sha256 为 1

Json::Value authen_info;
authen_info["a"] = authen; //认证码,签名是 s

Json::Value request; //构造最终发给服务器的请求
request["request_content"] = request_content_str;
request["authen_info"] = authen_info;

std::string request_str = w.write(request);

request_str 即为 post 内容。

请求内容示例:

{
    "authen_info":{
        "a":{
            "authen_code":"E84DCFDF546D0A0F91FFB90746F6FC7E9A8FCF62C4E682FE769BFB64486F72E5",
            "authen_type":1
        }
    },
    "request_content":"{
        "app_cpay_version":"1.0.0",
        "cellid":"eee",
        "lac":"ddd",
        "mcc":"bbb",
        "mnc":"ccc",
        "nonce_str":"ea90ceba",
        "rss":"fff",
        "sn_code":"aaa",
        "timestamp":1568859333
    }"
}

应答内容示例:

{
    "response_content":"{
        "status":0,
        "description":"",
        "log_id":18654852,
        "internal_status":0,
        "generate_bill_device_bind_qr_code":"{
            "activator":"p9fa01zex4mi",
            "token":"8azip8115bq",
            "ttl":180,
            "mini_program_url":"https://payapp.weixin.qq.com/smartqr/entry/home",
            "interval":1
        }"
    }",
    "authen_info":{
        "a":{
            "authen_type":1,
            "authen_code":"xxxx"
        }
    }
}

9.5 获取绑定信息

接口地址

https://pay.qcloud.com/cpay/get_bill_device_bind_info

请求参数

参数名 必填 类型 长度 说明
request_content String - 请求内容,该 string 可以转为 json 结构,json 格式见本节 RequestContent。
authen_info AuthenInfo - 认证信息,详见“初始密钥认证信息”。

RequestContent 结构

参数名 必填 类型 长度(Byte) 说明
sn_code String - 机具自身的 sn,注意要是完整的 sn,如LANDI_QM800_LA19**********POPSECU_SL51_BP51********
token String 12 generate_bill_device_bind_qr_code 接口应答中的 token。
nonce_str String 8 随机字符串,ASCII 字符(0-9、a-z、A-Z)。
timestamp Int 8 机具系统当前时间,UNIX 时间戳,单位为秒,如1568810504。

应答参数

参数名 必填 类型 长度(Byte) 说明
response_content ResponseContent - 应答内容,详见本节 ResponseContent。
authen_info AuthenInfo - 认证信息,详见“初始密钥认证信息”。

ResponseContent 结构

参数名 必填 类型 长度(Byte) 说明
status Int 4 错误码。
description String 最长128 错误信息。
log_id Int 4 消息 ID。
internal_status Int 4 具体说明见 internal_status 错误码表。
get_bill_device_bind_info_response String - 只有 status 为0的时候才存在,具体见 GetBillDeviceBindInfoResponse 说明。

GetBillDeviceBindInfoResponse

参数名 必填 类型 长度(Byte) 说明
activated Int 4 后台是否绑定完成,0-未完成,1-已完成。
out_mch_id String 最长64 云支付内部的服务商 ID,只当 activated 为1时才有。
out_sub_mch_id String 最长64 云支付内部的子商户 ID,只当 activated 为1时才有。
cloud_cashier_id String 最长64 云支付规定的定单前缀,只当 activated 为1时才有。
authen_type Int 4 子商户与云支付之间的签名算法类型,只当 activated 为1时才有。
e_authen_key String 最长256 Aes128CBC 加密并 base64 编码之后的支付密钥,机具先 base64 解码后,再使用初始化密钥来解密这个字段,以获得支付密钥(authen_key)。支付用这个密钥来计算签名。只当 activated 为1时才有。
out_shop_id String 最长64 云支付系统全局唯一门店 ID,只当 activated 为1时才有。
shop_name String 最长128 门店名称,只当 activated 为1时才有。
device_id String 最长64 设备 ID,只当 activated 为1时才有。
device_name String 最长256 设备名称,只当 activated 为1时才有。
staff_id String 最长64 店员 ID,保留字段,暂未使用。
staff_name String 最长256 店员名称,保留字段,暂未使用。
device_shift_type Int 4 设备类型,只当 activated 为1时才有。
nonce_str String 32 随机字符串,ASCII 字符(0-9、a-z、A-Z)。

示例说明

请求生成示例代码:

Json::Value request_content;
request_content["sn_code"] = "aaa";
request_content["token"] = "8azip8115bq";
request_content["nonce_str"] = "ea90ceba";    // 8字节随机字符串
request_content["timestamp"] = 1568859333;    // 当前系统时间

Json::FastWriter w;
std::string request_content_str = w.write(request_content);
std::string authen_code = hmac_sha256(init_key, request_content_str); // 使用机具初始密钥计算签名

Json::Value authen;
authen["authen_code"] = authen_code
authen["authen_type"] = 1; //hmac_sha256 为 1

Json::Value authen_info;
authen_info["a"] = authen; //认证码,签名是 s

Json::Value request; //构造最终发给服务器的请求
request["request_content"] = request_content_str;
request["authen_info"] = authen_info;

std::string request_str = w.write(request);

request_str 即为 post 内容。

请求内容示例:

{
    "authen_info":{
        "a":{
            "authen_code":"09E33D5E1D208569EE634C733F0B1FD933DD690B25F5BF72B386257B7A2113B0",
            "authen_type":1
        }
    },"
    request_content":"{
        "nonce_str":"ea90ceba",
        "sn_code":"aaa",
        "timestamp":1568859333,
        "token":"8azip8115bq"
    }"
}

应答内容示例:

{
    "response_content":"{
        "status":0,
        "description":"",
        "log_id":18654852,
        "internal_status":0,
        "bill_device_bind_sn" : "{
            "activated":1,
            "out_mch_id":"aaa",
            "out_sub_mch_id":"bbb",
            "cloud_cashier_id":"ccc",
            "authen_type":1,
            "authen_key":"ddd",
            "out_shop_id":"eee",
            "shop_name":"fff",
            "device_id":"ggg",
            "device_name":"hhh",
            "device_shift_type":1,
            "nonce_str":"416492026bc84091bcaf7e74ea90ceba"
        }"
    }",
    "authen_info":{
        "a":{
            "authen_type":1,
            "authen_code":"xxxx"
        }
    }
}

9.6 刷卡支付

接口地址

https://pay.qcloud.com/cpay/brief_micro_pay

请求参数

参数名 必填 类型 长度 说明
r RequestContent - 请求内容,详见本节 RequestContent。
a string - 使用支付密钥计算的认证码,目前只支持 sha256 计算认证码。

RequestContent 结构

参数名 必填 类型 长度(Byte) 说明
sc String - 机具的 sn,注意要是完整的 sn,如:LANDI_QM800_LA19**********POPSECU_SL51_BP51********
osi String - 云支付分配的门店全局 ID,由绑定成功时获取。
ns String 32 随机字符串,ASCII 字符(0-9、a-z、A-Z)。
otn String - 由调用方生成的订单号,前缀必须是绑定成功时获取的云支付订单前缀。
ac String - author_code,刷卡支付时顾客的付款码。云支付后台通过这个字段来区分是微信支付,或支付宝支付还是会员卡支付。
tf Int 8 即 total_fee,订单总金额,单位分。
bd String - 即 body,商品或订单简要描述。
di String - 即 device_id,设备编号,由绑定成功时获取。
stt Int - 即 sub_terminal_type,子终端类型,代表一个机具品牌,由云支付分配,详见 5.1 申请初始资源

应答参数

参数名 必填 类型 长度(Byte) 说明
rc ResponseContent - 请求内容,详见本节 ResponseContent。
a String 32 认证码,目前只支持 sha256 计算认证码。

ResponseContent 结构

参数名 必填 类型 长度(Byte) 说明
s Int 4 错误码。
d String 最长128 即 description,错误信息。
li Int 4 即 log_id,消息 ID。
is Int 4 具体说明见 internal_status 错误码表。
brief_micro_pay BriefMicroPayResponse - 详见本节 BriefMicroPayResponse。

BriefMicroPayResponse

参数名 必填 类型 长度(Byte) 说明
wx BriefWxpayOrderContentExt - 详见 BriefWxpayOrderContentExt。
ali BriefAlipayOrderContentExt - 详见 BriefAlipayOrderContentExt。
cd BriefCardOrderContentExt - 详见 BriefCardOrderContentExt。
ns String 8 8字节随机字符串。

示例说明

请求生成示例代码:

Json::Value request_content;
request_content["ns"] = generate_random_nonce_str();
request_content["osi"] = out_shop_id;
request_content["otn"] = out_trade_no;
request_content["ac"] = author_code;
request_content["tf"] = total_fee;
request_content["bd"] = body;
request_content["di"] = device_id;
request_content["sc"] = sn_code;
request_content["stt"] = sub_terminal_type;
Json::FastWriter w;
const std::string &rc = w.write(request_content);
std::string authen_code = hmac_sha256(authen_key, rc); // 计算签名
Json::Value request;
request["r"] = rc;
request["a"] = authen_code;
return w.write(request);

请求内容示例:

{
    "r":"{
        "ns":"69050786d195198efe9070ae45857070",
        "osi":"sz01QgJZkxDB7RVeL6XY",
        "otn":"0100826651692015704554111",
        "ac":"135005875955002257",
        "tf":900,
        "bd":"支付简述",
        "di":"tdFQtGl2M9MOcgTn",
        "sc":"LANDI_QM800_LA198KBQ8W1666",
        "stt":2451
    }",
    "a":"A4BCE4DF5C59C1D1532FA38D5C0298E46F224D02D38EFA6A766A5368271413B1"
}

应答内容示例:

{
    "rc":"{
        "s":0,
        "d":"xxx",
        "li":2643575008,
        "is":0,
        "brief_micro_pay":{
            "wx":{
                "cts":2
            },
            "ns":"dJMSHgYs"
        }
    }",
    "a":"4E80102BC41267241DE4B55AC40A5B2952C2F739E384767DDD065B8E1189846A"
}

9.7 查询支付单

接口地址

https://pay.qcloud.com/cpay/brief_query_order

请求参数

参数名 必填 类型 长度 说明
r RequestContent - 请求内容,详见本节 RequestContent。
a string - 使用支付密钥计算的认证码,目前只支持 hmac-sha256 计算认证码。

RequestContent 结构

参数名 必填 类型 长度(Byte) 说明
osi String - 云支付分配的门店全局 ID,由绑定成功时获取。
ns String 32 随机字符串,ASCII 字符(0-9、a-z、A-Z)。
otn String - 由调用方生成的支付订单号。

应答参数

参数名 必填 类型 长度(Byte) 说明
rc ResponseContent - 请求内容,详见本节 ResponseContent。
a String 32 使用支付密钥计算的认证码,目前只支持 hmac-sha256 计算认证码。

ResponseContent 结构

参数名 必填 类型 长度(Byte) 说明
s Int 4 错误码。
d String 最长128 即 description,错误信息。
li Int 4 即 log_id,消息 ID。
is Int 4 具体说明见 internal_status 错误码表。
brief_query_order BriefQueryOrderResponse - 详见本节 BriefQueryOrderResponse。

BriefQueryOrderResponse

参数名 必填 类型 长度(Byte) 说明
pp Int 4 第三方支付平台,详细见 PayPlatform。
otn String - 由支付调用户生成的订单号。
tf Int 8 订单总金额,单位为分。
wx BriefWxpayOrderContentExt - 详见 BriefWxpayOrderContentExt。
ali BriefAlipayOrderContentExt - 详见 BriefAlipayOrderContentExt。
cd BriefCardOrderContentExt - 详见 BriefCardOrderContentExt。
ns String 8 8字节随机字符串。

示例说明

请求生成示例代码:

Json::Value request_content;
request_content["ns"] = generate_random_nonce_str();
request_content["osi"] = out_shop_id;
request_content["di"] = device_id;
request_content["sc"] = sn_code;
request_content["otn"] = out_trade_no;

Json::FastWriter w;
const std::string &rc = w.write(request_content);

std::string authen_code = hmac_sha256(authen_key, rc); // 计算签名

Json::Value request;
request["r"] = rc;
request["a"] = authen_code;
return w.write(request);

请求内容示例:

{
    "r":"{
        "ns":"92f7ba8154a4532d97cb6f2b181309e9",
        "otn":"013907131297815704553502",
        "osi":"sz015Xco0HsfMcFGkeB9"
    }",
    "a":"D9C1233C5D08288A00975F61DF328E7E76F426C3519284A1F43245703F7CFCFE"
}

应答内容示例:

{
    "rc":"{
        "s":0,
        "d":"u64CDu4F5Cu6210u529Fu3002",
        "li":2185455507,
        "is":0,
        "brief_query_order":{
            "otn":"013907131297815704553502",
            "tf":240000,
            "pp":2,
            "ali":{
                "cts":4
            },
            "ns":"sclBgLM9"
        }
    }",
    "a":"C8A4986C17BAB6F88623CBA0F89C375288F972C43181E193A22EC6BDA25CFDAA"
}

9.8 退款

接口地址

https://pay.qcloud.com/cpay/refund

说明文档链接

申请退款

9.9 查询退款单

接口地址

https://pay.qcloud.com/cpay/query_refund_order

说明文档链接

查询退款单

9.10 支付信息上报

接口地址

https://pay.qcloud.com/cpay/device_report

请求参数

参数名 必填 类型 长度 说明
request_content RequestContent - 请求内容,该 string 可以转为 json 结构,json 格式见本节 RequestContent。
authen_info Authen_info - 认证信息,详见“支付密钥认证信息”。

RequestContent 结构

参数名 必填 类型 长度(Byte) 说明
device_type Int 4 设备类型:1-移动收款机具。
company_code String - 公司简码,4.1节中有说明。
model String - 型号简码,4.1节中有说明。
sn String - 完整 sn,4.1节中有说明。
begin_timestamp Int 8 统计开始时间,UNIX 时间戳,单位为秒,如1568810504。
end_timestamp Int 8 统计结束时间,UNIX 时间戳,单位为秒,如1568810504。
sim_number String - Sim 卡号,即 ICCID 号。
cpu_usage Int 4 当前 CPU 使用率0-100。
mem_max Int 4 最大内存 KB。
mem_in_use Int 4 当前已用内存 KB。
disk_max Int 4 最大硬盘 KB。
disk_in_use Int 4 当前已用硬盘 KB。
network_type String - 支付所使用的网络类型:wifi、2g、3g、4g等。
upload_net_flow Int 4 累计上传流量。
download_net_flow Int 4 累计下载流量。
mcc String - 基站国家码,十进制数字字符串。
mnc String - 基站网络码,十进制数字字符串。
lac String - 基站小区号,十进制数字字符串。
cellid String - 基站 ID,十进制数字字符串。
rss String - 基站信号强度,单位 dbm,十进制数字字符串。
longitude String - 经度。
latitude String - 纬度。
wx_pay_count Int 4 累计微信支付笔数,上报后清零计数。
wx_pay_success_count Int 4 累计微信支付成功笔数,上报后清零计数。
ali_pay_count Int 4 累计支付宝笔数,上报后清零计数。
ali_pay_success_count Int 4 累计支付宝成功笔数,上报后清零计数。
other_pay_count Int 4 累计其他支付笔数,上报后清零计数。
other_pay_success_count Int 4 累计其他支付成功笔数,上报后清零计数。
wx_pay_amount Int 8 累计微信支付金额,单位分,上报后清零计数。
ali_pay_amount Int 8 累计支付宝金额,上报后清零计数。
other_pay_amount Int 8 累计其他支付金额,上报后清零计数。
out_mch_id String - 云支付服务商号,绑定成功时获取。
out_sub_mch_id String - 云支付子商户号,绑定成功时获取。
cloud_cashier_id String - 云支付分配给商户订单前缀,绑定成功时获取。
authen_type Int 4 签名类型1:HMAC-SHA256,绑定成功获取。
out_shop_id String - 云支付门店全局 ID,绑定成功时获取。
device_id String - 云支付设备 ID,绑定成功时获取。
staff_id String - 云支付店员 ID,绑定成功时获取,有可能没有。
app_cpay_version String - 云支付统一分配的版本号。
api_calling_infos ApICallingInfo - 接口调用数据,见 ApiCallingInfo。

ApiCallingInfo 结构

参数名 必填 类型 长度(Byte) 说明
out_trade_no String - 支付时的订单号。
code Int 4 如果能正常获取 HTTP 的状态码(如200、404、405之类)则用状态码填充,其它情况:连接失败填(-2),接口获取应答超时填(-3),未知问题填(-4)。
status Int 4 brief_micro_pay 应答的一级错误码,应答中 s 字段。
internal_status Int 4 brief_micro_pay 应答的二级错误码,应答中 is 字段。
delay_ms Int 4 从扫用户收款码开始到获取到 brief_micro_pay 接口应答中间的耗时,单位为毫秒。
description String - brief_micro_pay 应答中的 d 字段内容。
pay_platform Int 4 支付方式,见 PayPlatform 说明。
order_status Int 4 支付完成最后一次云支付接口(可能是 brief_micro_pay 或 brief_query_order)返回的订单状态,即 cts 字段内容。
trade_state_desc String - 支付完成最后一次云支付接口(可能是 brief_micro_pay 或 brief_query_order)返回的订单状态描述,即 tsd 字段内容。

应答参数

参数名 必填 类型 长度(Byte) 说明
response_content ResponseContent - 应答内容,详见本节 ResponseContent。
authen_info AuthenInfo - 认证信息,详见“支付密钥认证信息”。

ResponseContent 结构

参数名 必填 类型 长度(Byte) 说明
status Int 4 错误码。
description String 最长128 错误信息。
log_id Int 4 消息 ID。
internal_status Int 4 具体说明见 internal_status 错误码表。

示例说明

请求生成示例代码:

Json::Value request_content;
request_content["device_type"] = 1;
request_content["company_code"] = "aa";
request_content["model"] = "bb";
request_content["sn"] = "cc";
request_content["sim_number"] = "dd";
request_content["cpu_usage"] = 33;
request_content["mem_max"] = 100000;
request_content["mem_in_use"] = 2000;
request_content["disk_max"] = 200000;
request_content["disk_in_use"] = 39999;
request_content["network_type"] = "ccc";
request_content["upload_net_flow"] = 33333;
request_content["download_net_flow"] = 4444444;
request_content["mcc"] = "fff";
request_content["mnc"] = "ggg";
request_content["lac"] = "aaa";
request_content["cellid"] = "bbb";
request_content["rss"] = "ccc";
request_content["longitude"] = "ddd";
request_content["latitude"] = "eee";
request_content["begin_timestamp"] = 1553268531;
request_content["end_timestamp"] = 1553268531;
request_content["wx_pay_count"] = 11;
request_content["wx_pay_success_count"] = 11;
request_content["ali_pay_count"] = 12;
request_content["ali_pay_success_count"] = 12;
request_content["other_pay_count"] = 13;
request_content["other_pay_success_count"] = 13;
request_content["wx_pay_amount"] = 22;
request_content["ali_pay_amount"] = 23;
request_content["other_pay_amount"] = 24;
request_content["out_mch_id"] = "gggg";
request_content["out_sub_mch_id"] = "a1";
request_content["cloud_cashier_id"] = "b1";
request_content["authen_type"] = 1;
request_content["out_shop_id"] = "d1";
request_content["device_id"] = "e1";
request_content["staff_id"] = "f1";
request_content["device_shift_type"] = "g1";
request_content["nonce_str"] = "416492026bc84091bcaf7e74ea90ceba";

Json::Value info_0;
info_0["out_trade_no"] = "EEEEEEEEEEEEEE";
info_0["code"] = 200;
info_0["status"] = 2;
info_0["internal_status"] = 2;
info_0["delay_ms"] = 200;
info_0["description"] = "操作成功";
info_0["pay_platform"] = 1;
info_0["order_status"] = 3;
info_0["trade_state_desc"] = "支付成功";

request_content["api_calling_infos"].append(info_0);

Json::Value info_1;
info_1["out_trade_no"] = "FFFFFFFF";
info_1["code"] = 200;
info_1["status"] = 22;
info_1["internal_status"] = 22;
info_1["delay_ms"] = 300;
info_1["description"] = "xxxx";
info_1["pay_platform"] = 1;
info_1["order_status"] = 3;
info_1["trade_state_desc"] = "xxx";

request_content["api_calling_infos"].append(info_1);

Json::FastWriter w;
std::string request_content_str = w.write(request_content);
std::string authen_code = hmac_sha256(authen_key, request_content_str); // 计算签名

Json::Value authen;
authen["authen_code"] = authen_code;
authen["authen_type"] = 1; //统一使用 hmac_sha256,填1

Json::Value authen_info;
authen_info["a"] = authen;  //key 填”a”就行,表示认证码

Json::Value request;
request["request_content"] = request_content_str;
request["authen_info"]  = authen_info;
std::string request_str = w.write(request);

request_str 即为 post 内容。

请求内容示例:

{
    "request_content":"{
        "nonce_str":"4db12671e9510667d9c8d65bdf50a27b",
        "company_code":"LANDI",
        "model":"LANDI_QM600",
        "sn":"LANDI_QM600_LA197LB331212",
        "begin_timestamp":1570458756,
        "end_timestamp":1570462751,
        "network_type":"wifi",
        "mcc":"460",
        "mnc":"00",
        "lac":"2733",
        "cellid":"3437",
        "rss":"-79",
        "sim_number":"89860412101871062566",
        "wx_pay_count":1,
        "wx_pay_success_count":1,
        "ali_pay_count":0,
        "ali_pay_sucess_count":0,
        "ali_pay_amount":0,
        "other_pay_count":0,        
        "other_pay_success_count":0,
        "other_pay_amount":0,
        "out_mch_id":"sz01M43ouf007JL1sn33",
        "out_sub_mch_id":"sz01NI6PoQVvYEmOcoRp",
        "cloud_cashier_id":"010110893",
        "authen_type":1,
        "out_shop_id":"sz01aZk73lnFVxX6XSWp",
        "device_id":"kUwbvm1cpdGn4Kxm",
        "device_type":1,
        "device_shift_type":1,
        "app_cpay_version":"1.0.0",
        "api_calling_infos":[
            {
                "out_trade_no":"0101108936210615704627481",
                "code":200,
                "status":0,
                "internal_status":0,
                "delay_ms":2060
            }
        ]
    }",
    "authen_info":{
        "a":{
            "authen_type":1,
            "authen_code":"C80A72B0A7858D2D84E26093F562516C64DB1D319534A7D1B9ACF17556226019"
        }
    }
}

应答内容示例:

{
    "response_content":"{
        "status":0,
        "description":"xxxx",
        "log_id":973138369,
        "internal_status":0,
        "device_info_report":{
            "nonce_str":"4dOOZyhxzTRexn5OBDqA8vhve3FqnCHL"
        }
    }",
    "authen_info":{
        "a":{
            "authen_type":1,
            "authen_code":"5E417C5D6FE523982C3507A22D762F3215255F752C3CD4DC37C7792D964418C3"
        }
    }
}

9.11 查询订单明细

接口地址

https://pay.qcloud.com/cpay/brief_query_order_list

请求参数

参数名 必填 类型 长度 说明
r RequestContent - 请求内容,详见本节 RequestContent。
a string - 使用支付密钥计算的认证码,目前只支持 hmac-sha256 计算认证码。

RequestContent 结构

参数名 必填 类型 长度(Byte) 说明
spps Int [] 单个元素4 sub_pay_platforms:子支付平台列表,100:普通微信支付,200:普通支付宝,300:会员卡,机具填写这三个值即可。
osmi String - out_sub_mch_id:云支付分配的商户 ID,绑定成功后可获取此 ID。
osi String - out_shop_id:云支付分配的门店 ID,绑定成功后可获取此 ID。
di String - device_id:云支付分配的设备ID,绑定后可获取此 ID。
ot Int 4 order_type:单据类型,1:支付订单,2:退款单,3:全部单据。
st Int 8 start_time:查询开始时间。
et Int 8 end_time:查询结束时间。
pn Int 4 page_num:页码,必需大于0。
ps Int 4 page_size:单页条数,必需大于0。
tt Int 4 交易类型,1:刷卡支付,2:扫码支付,3:公众号支付,4:App 支付,5:声波支付, 6:H5 支付,8:一码付支付,9:小程序支付。机具应填1。
ns String 32 随机字符串,ASCII 字符(0-9、a-z、A-Z)。

应答参数

参数名 必填 类型 长度(Byte) 说明
rc ResponseContent - 请求内容,详见本节 ResponseContent。
a String 32 使用支付密钥计算的认证码,目前只支持 hmac-sha256 计算认证码。

ResponseContent 结构

参数名 必填 类型 长度(Byte) 说明
s Int 4 错误码。
d String 最长128 即 description,错误信息。
li Int 4 即 log_id,消息 ID。
is Int 4 具体说明见 internal_status 错误码表。
brief_query_order_list BriefQueryOrderListResponse - 详见本节 BriefQueryOrderListResponse。

BriefQueryOrderResponse

参数名 必填 类型 长度(Byte) 说明
tc Int 4 total_count:订单总数。
ods OrderDetail [] - order_details:见 OrderDetail 说明。
ns String 32 随机字符串,ASCII 字符(0-9、a-z、A-Z)。

OrderDetail

参数名 必填 类型 长度(Byte) 说明
bo BriefOrder - 订单结构体,见本节 BriefOrder。
bro BriefRefundOrder - 退款单结构体, 见本节 BriefRefundOrder。

order、refund_order 只包含一个。

BriefOrder

参数名 必填 类型 长度(Byte) 说明
spp Int 4 sub_pay_platform:子支付平台,100:普通微信支付,200:普通支付宝,300:会员卡。
tt Int 4 trade_type:交易类型,1:刷卡支付,2:扫码支付,3:公众号支付,4:App 支付,5:声波支付, 6:H5 支付,8:一码付支付,9:小程序支付。
otn String 32 out_trade_no:支付单号。
tf Int 8 total_fee:订单总金额。
ct Int 8 create_time:订单创建时间。
wx_cts Int 4 wxpay_current_trade_state:见枚举值定义 WxpayOrderState。
ali_cts Int 4 支付宝订单状态,见枚举值定义 AlipayOrderState。

BriefRefundOrder

参数名 必填 类型 长度(Byte) 说明
spp Int 4 sub_pay_platform:子支付平台,100:普通微信支付,200:普通支付宝,300:会员卡。
tt Int 4 trade_type:交易类型,1:刷卡支付,2:扫码支付,3:公众号支付,4:App 支付,5:声波支付, 6:H5 支付,8:一码付支付,9:小程序支付。
otn String 32 out_trade_no:支付单号。
tf Int 8 total_fee:订单总金额。
orn String 32 out_refund_no:退款单号。
rf Int 8 refund_fee:本次退款总金额。
ct Int 8 create_time:退款单创建时间。
wx_rs Int 4 wxpay_refund_state:微信退款状态,见枚举值定义 WxpayRefundOrderState。
ali_rs Int 4 alipay_refund_state:支付宝退款状态,见枚举值定义 AlipayRefundOrderState。

示例说明

请求生成示例代码:

Json::Value request_content;
request_content["spps"].append(100);
request_content["spps"].append(200);
request_content["osmi"] = "sz0138zjfiwezee";
request_content["osi"] = "sz01FzZfei91";
request_content["di"] = "FzZfei91iefaefz";
request_content["ot"] = 1;
request_content["st"] = 1571817655;
request_content["et"] = 1571817755;
request_content["pn"] = 1;
request_content["ps"] = 2;
request_content["tt"] = 1;
request_content["ns"] = generate_random_nonce_str();

Json::FastWriter w;
const std::string &rc = w.write(request_content);

std::string authen_code = hmac_sha256(authen_key, rc); // 支付密钥计算签名

Json::Value request;
request["r"] = rc;
request["a"] = authen_code;
return w.write(request);

请求内容示例:

{    
    "a":"6A664293966BECE1D72CA468F2B3CD8283113BE4CDF7BC0153C28F29C77054B8",
    "r":"{
        "spps":[100,200],
        "osmi":"sz0138zjfiwezee",
        "osi":"sz01FzZfei91",
        "di":"FzZfei91iefaefz",
        "ot":1,
        "st":1571817655,
        "et":1571817755,
        "pn":1,
        "ps":2,
        "tt":1,
        "ns":"faeofeifazfeijfi"
    }"
}

应答内容示例:

{
    "a":"C6E3976196205719D36909D706206132EFDCFC6B672E45FC05CFDE5933BB8F18",
    "rc":"{
        "tc":102,
        "ods":[
            {
                "bo":{
                    "spp":100,
                    "tt":1,
                    "otn":"110138591298768",
                    "spp":100,
                    "tt":1,
                    "otn":"110138591298768",
                    "tf":200,
                    "ct":1571817657,
                    "wx_cts":2
                }
            },
            {
                "bro":{
                    "spp":200,
                    "tt":1,
                    "otn":"110187443881321",
                    "tf":300,
                    "orn":"110187812300831",
                    "rf":100,
                    "ct":1571817660,
                    "ali_rs":2
                }
            }
        ],
        "ns":"faeofeifazfeijfi"
    }"
}

9.12 查询订单汇总

接口地址

https://pay.qcloud.com/cpay/brief_query_order_list_overview

请求参数

参数名 必填 类型 长度 说明
r RequestContent 请求内容,详见本节 RequestContent。
a string 使用支付密钥计算的认证码,目前只支持 hmac-sha256 计算认证码。

RequestContent 结构

参数名 必填 类型 长度(Byte) 说明
spps Int [] 单个元素4 sub_pay_platforms:子支付平台列表,100:普通微信支付,200:普通支付宝,300:会员卡,机具填上这三个值就行。
osmi String - out_sub_mch_id:云支付分配的商户 ID,绑定成功后可获取此 ID。
osi String - out_shop_id:云支付分配的门店 ID,绑定成功后可获取此 ID。
di String - device_id:云支付分配的设备 ID,绑定后可获取此 ID。
ot Int 4 order_type: 单据类型,1:支付订单,2:退款单,3:全部单据。
st Int 8 start_time:查询开始时间。
et Int 8 end_time:查询结束时间。
tt Int 4 交易类型,1:刷卡支付,2:扫码支付,3:公众号支付,4:App 支付,5:声波支付, 6:H5 支付,8:一码付支付,9:小程序支付。机具应填1。
ns String 32 随机字符串,ASCII 字符(0-9、a-z、A-Z)。

应答参数

参数名 必填 类型 长度(Byte) 说明
rc ResponseContent - 请求内容,详见本节 ResponseContent。
a String 32 使用支付密钥计算的认证码,目前只支持 hmac-sha256 计算认证码。

ResponseContent 结构

参数名 必填 类型 长度(Byte) 说明
s Int 4 错误码。
d String 最长128 即 description,错误信息。
li Int 4 即 log_id,消息 ID。
is Int 4 具体说明见 internal_status 错误码表。
brief_query_order_list BriefQueryOrderListResponse - 详见本节 BriefQueryOrderListResponse。

BriefQueryOrderResponse

参数名 必填 类型 长度(Byte) 说明
ovs OrderStatClientInfo [] - overviews:见 OrderStatClientInfo 说明。
ns String 32 随机字符串,ASCII 字符(0-9、a-z、A-Z)。

OrderStatClientInfo

参数名 必填 类型 长度(Byte) 说明
spp Int 4 sub_pay_platform:子支付平台,100:普通微信支付,200:普通支付宝,300:会员卡。
tt Int 4 trade_type:交易类型,1:刷卡支付,2:扫码支付,3:公众号支付,4:App 支付,5:声波支付, 6:H5 支付,8:一码付支付,9:小程序支付。
sc Int 8 success_count:(交易量)不含撤单的,扣款成功交易笔数,有可能是负值。
sa Int 8 success_amount:不含撤单的,扣款成功交易金额,有可能是负值。
sta Int 8 settlement_amount:操作人扣款成功结算金额 - 操作人退款结算金额 - 操作人扣款成功撤单结算金额。
da Int 8 discount_amount:必返回 net_amount - settle_amount。
psa Int 8 pay_settle_amount,扣款成功结算金额。
rsa Int 8 refund_settle_amount,扣款成功结算金额。
rcc Int 8 refund_create_count,退款发起笔数。
rca Int 8 refund_create_amount,退款发起总额。
pdg Int 8 poundage,扣款成功手续费 - 撤单返还手续费 - 退款成功返还的手续费,有可能是负值。
ia Int 8 income_amount,入账金额。
ora Int 8 order_refunded_amount,订单已退金额。

示例说明

请求生成示例代码:

Json::Value request_content;
request_content["spps"].append(100);
request_content["spps"].append(200);
request_content["osmi"] = "sz0138zjfiwezee";
request_content["osi"] = "sz01FzZfei91";
request_content["di"] = "FzZfei91iefaefz";
request_content["ot"] = 1;
request_content["st"] = 1571817655;
request_content["et"] = 1571817755;
request_content["tt"] = 1;
request_content["ns"] = generate_random_nonce_str();

Json::FastWriter w;
const std::string &rc = w.write(request_content);

std::string authen_code = hmac_sha256(authen_key, rc); // 支付密钥计算签名

Json::Value request;
request["r"] = rc;
request["a"] = authen_code;
return w.write(request);

请求内容示例:

{
    "a":"156073D9F354BF8000E1EF82AC82EDB2836A9D6DF7CDFD33B05ED5DFE3407516",
    "r":"{
        "spps":[100,200],
        "osmi":"sz0138zjfiwezee",
        "osi":"sz01FzZfei91",
        "di":"FzZfei91iefaefz",
        "ot":1,
        "st":1571817655,
        "et":1571817755,
        "tt":1,
        "ns":"faeofeifazfeijfi"
    }"
}

应答内容示例:

{
    "a":"883E4B4406668C45EECCC331A8967A4A64F07BA79B4F24395A39192F28D0F231",
    "rc":"{
        "ovs":[
            {
                "spp":200,
                "tt":1,
                "sc":4,
                "sa":2400,
                "sta":2400,
                "da":0,
                "psa":2400,
                "rsa":2100,
                "rcc":1,
                "rca":300,
                "pdg":200,
                "ia":1900,
                "ora":300
            },
            {
                "spp":100,
                "tt":1,
                "sc":14,
                "sa":9100,
                "sta":9100,
                "da":100,
                "psa":9100,
                "rsa":8100,
                "rcc":1,
                "rca":300,
                "pdg":200,
                "ia":8000,
                "ora":500
            }
        ],
        "ns":"ZMEEOPPfeaeiwf122"
    }"
}

9.13 其它消息体说明

WxpayOrderContentExt

参数名 必填 类型 长度(Byte) 说明
cts Int 4 订单当前状态,详见 WxpayOrderState。
tsd String 256 对当前查询订单状态描述和下一步操作指引。

AlipayOrderContentExt

参数名 必填 类型 长度(Byte) 说明
cts Int 4 订单当前状态,详见 AlipayOrderState。

CardOrderContentExt

参数名 必填 类型 长度(Byte) 说明
cts Int 4 订单当前状态,详见 CardOrderState。

初始密钥认证信息

参数名 必填 类型 长度(Byte) 说明
a Authen - 认证信息,见本节 Authen。

Authen 结构

参数名 必填 类型 长度(Byte) 说明
authen_type Int 4 签名类型1:HMAC-SHA256。
authen_code String 32 使用机具初始密钥计算的认证码,初始密钥说明见4.2节。

支付密钥认证信息

参数名 必填 类型 长度(Byte) 说明
a Authen - 认证信息,见本节 Authen。

Authen 结构

参数名 必填 类型 长度(Byte) 说明
authen_type Int 4 签名类型1:HMAC-SHA256。
authen_code String 32 使用机具初始密钥计算的认证码,支付密钥说明见4.3节。

Status

枚举值 操作结果 返回内容是否带认证码 原请求是否能重试 用户操作建议
0 成功 -
3 未知 原请求重试。
101 失败 根据 description 内容,检查调用逻辑是否有问题,如认证码计算错误。
102 失败 换新单号重试,并根据 description 字段内容,检查调用逻辑是否有问题,如单号重复。
103 失败 隔3秒后原请求重试或查询结果。
104 失败 根据 description 字段内容操作,如退款时顾客余额不足。

WxpayOrderState

枚举值 说明
1 订单初始态。
2 刷卡支付,成功。
3 统一下单,支付成功。
4 已转入退款。
5 刷卡支付,顾客停止支付。
6 统一下单,待顾客支付。
7 统一下单,订单已关闭。
8 刷卡支付,已撤单。
9 刷卡支付,用户支付中。
10 刷卡支付,支付错误。
11 作废状态,表示本地有,第三方支付平台没有的订单。

AlipayOrderState

枚举值 说明
1 订单初始态。
2 成功。
4 等待用户支付。
5 已关闭,或者已退款。
6 交易结束,不可退款。
7 订单不存在。

CardOrderState

枚举值 说明
1 订单初始态。
2 成功。
3 等待用户支付。
4 已退款。
5 已关单。

PayPlatform

枚举值 说明
1 微信支付。
2 支付宝。
3 会员卡。

WxpayRefundOrderState

枚举值 说明
1 退款单初始态。
2 退款成功。
3 退款失败。
4 退款处理中。
5 转入代发,退款到银行发现用户的卡作废或冻结了,导致原路退款银行卡失败,资金回流到子商户的现金帐号,需要子商户人工干预,通过线下或者财付通转账的方式进行退款。
6 作废状态,表示本地有,第三方支付平台没有的订单。

AlipayRefundOrderState

枚举值 说明
1 退款单初始态。
2 退款成功。
3 退款失败。
4 退款处理中。
5 订单不存在。

10 加解密相关说明

10.1 AES-128-CBC 解密说明

  • 算法:AES-128
  • 模式:CBC
  • 填充类型:PKCS5Padding
  • 盐(salt):要解密的内容前8字节为盐,剩余字节内容为原始明文内容的加密内容。

示例代码如下:

bool aes_128_cbc_decrpty(
            const std::string &session_key,
            const std::string &input,
            std::string *output)
{
    assert(output);
    output->clear();
    output->reserve(input.length() + 24); // Space for salt + padding.

    unsigned char salt[8];
    size_t total = input.size();
    const char *inptr = input.data();

    if (input.length() < sizeof(salt)) {
        return false;
    }

    memcpy(salt, inptr, sizeof(salt));
    inptr += sizeof(salt);
    total -= sizeof(salt);

    unsigned char iv[16];
    unsigned char key[16];
    int ret = EVP_BytesToKey(EVP_aes_128_cbc(), EVP_sha1(), salt,
                             (const unsigned char *)session_key.data(),
                             session_key.length(),
                             1, key, iv);

    if (ret != sizeof(key)) {
        return false;
    }

    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    EVP_CIPHER_CTX_init(ctx);

    if (!EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 0)) {
        EVP_CIPHER_CTX_free(ctx);
        return false;
    }

    int outlen;
    unsigned char buffer[2560];
    for (size_t i = 0; i < total; i += 2048, inptr += 2048) {
        outlen = sizeof(buffer);
        unsigned char *in = (unsigned char *)inptr;
        int inlen = total - i < 2048 ? total - i : 2048;
        if (!EVP_CipherUpdate(ctx, buffer, &outlen, in, inlen)) {
            EVP_CIPHER_CTX_free(ctx);
            return false;
        }

        output->append(reinterpret_cast<const char *>(buffer), outlen);
    }

    outlen = sizeof(buffer);
    if (!EVP_CipherFinal_ex(ctx, buffer, &outlen)) {
        EVP_CIPHER_CTX_free(ctx);
        return false;
    }

    output->append(reinterpret_cast<const char *>(buffer), outlen);
    EVP_CIPHER_CTX_free(ctx);
    return true;
}