接口调用说明

最近更新时间:2019-11-06 17:44:31

通讯说明

  • 所有接口均使用 https 通信,数据包格式为 json(http 请求的 content-type 字段必须使用 application/json)。
  • 请求必须传认证信息,需要传认证码和认证算法。
  • 响应要验证认证码。
  • 所有接口参数名使用的字母均为小写。

数据包格式说明

请求包格式

请求格式示例(以 query_order 接口为例):

{  
    "authen_info": {  
        "a": {  
            "authen_type": 1,  
            "authen_code": "69E65DA0A32F18D059DBE81CA4D9D702470184966E12A03715584249788BD8DD"  
        }  
    },  
    "request_content": "{\"pay_mch_key\": {\"pay_platform\": 1, \"sub_pay_platform\": 100, \"out_shop_id\": \"sz011biKxOguirmBqiFR\", \"out_sub_mch_id\": \"sz01KzuCUOmw8yjtPite\", \"out_mch_id\": \"sz01lXKA6DKGjNzr2l4B\"}, \"trade_type\": 1, \"out_trade_no\": \"sz010002cz11564386781\", \"nonce_str\": \"E94C00688C3F429CA2B0B396BF823548\", \"order_client\": {\"staff_id\": \"1192\", \"machine_no\": \"1111\", \"terminal_type\": 1, \"sdk_version\": \"1.0\", \"device_id\": \"12345\", \"spbill_create_ip\": \"90.0.00.0\"}}"  
}  

详解:
请求包含两个字段:authen_info 和 request_content。前者表示认证信息,为 json 结构;后者表示请求具体内容,为 json 形式字符串化。

  • request_content 为具体请求内容的 json 字符串化结构,见各具体接口。
  • authen_info 结构有嵌套属性 a,字段为认证码:
    字段 类型 说明
    authen_type Number(32) 认证算法类型。只支持填1,即为 HMAC-SHA256
    authen_code String(64) 认证码
    认证码生成算法:HMAC-SHA256 认证密钥为服务商在云支付录入商户时,在网页上生成的认证密钥。

响应包格式

响应包与请求包类似,包含两个字段:authen_info 和 response_content。前者表示认证信息(响应包仅有认证码方式),为 json 结构;后者表示响应具体内容,为 json 形式字符串化。响应格式示例(以交接班接口为例):

{  
    "authen_info": {  
        "a":{  
            "authen_type": 1,  
            "authen_code" : "1CB622818DF1E2D91741A5FE792F1EFDD2557343FBD1275628E832A95CBB0FBC"  
        }  
    },  
    "response_content": "{\"status\":0,\"description\":\"\\u64CD\\u4F5C\\u6210\\u529F\\u3002\",\"log_id\":1167366844,\"internal_status\":0}"  
}  

其它说明

各种 update 接口中,如选填字段不填写,则该字段不需修改。清空此字段时,需上传此字段的内容为空。
接口调用说明
交易接口中的门店信息,必须和子商户在云支付手机端商户管理系统设置的一致。
订单和退款单号说明
为了保护不同商户的订单号不重复,云支付为每个服务商录入的子商户分配“云支付订单前缀”,在云支付后台的商户详情中可以看到,该商户的订单和退款单必须以云支付子商户号做前缀。

数据包构造示例

下面以刷卡支付为例来介绍整个认证过程:

客户端向服务器发送请求

  1. 判定使用场景。
    在这个示例中,我们要发出的是刷卡支付请求。因此,需要使用认证算法来计算认证码。
  2. 根据接口的输入参数,构造 json 格式字符串。
  3. 将 json 格式字符串转换为字符串,并使用认证算法,认证 key 来计算认证码。
  4. 构造 authen_info 结构。
  5. 构造 json 格式的请求数据包,需要包含 authen_info 和 request_content 字段。
  6. 将 json 格式请求转换为字符串,发送给服务器。

客户端验证服务器应答消息

  1. 将响应包从 string 转换为 json 格式消息。

  2. 取出 json 格式消息中的 authen_info 和 response_content 字段信息。

  3. 使用认证算法和认证 key 对 response_content 计算认证码。

  4. 将计算得到的认证码和 authen_info 中的 authen_code 进行比较;正确情况下,两者应该一致。

代码示例(C++)

构造请求字符串(以刷卡支付为例):

std::string MicroPay_request_str()  
{  
    /* 1.构造业务请求参数 */  
    Json::Value pay_mch_key;      // 构造 pay_mch_key  
    pay_mch_key["pay_platform"]   = 1;  
    pay_mch_key["out_mch_id"]     = "sz013NzuonO6CMJd0rCB";  
    pay_mch_key["out_sub_mch_id"] = "sz01ELTR281OFpmdAp6J";  
    pay_mch_key["out_shop_id"]    = "sz01qyoPJmd3j1hWmul4";  
    Json::Value pay_content;      // 构造 pay_content  
    pay_content["out_trade_no"]   = "sz0100lmnx20171228151031";  
    pay_content["author_code"]    = "134680423163089456";  
    pay_content["total_fee"]      = 1;  
    pay_content["fee_type"]       = "CNY";  
    pay_content["attach"]         = "attach";  
    Json::Value order_client;        // 构造 order_client  
    order_client["machine_no"]       = "32-62-A8-14-B3-C0";  
    order_client["sdk_version"]      = "1.0";  
    order_client["device_id"]        = 1;  
    order_client["spbill_create_ip"] = "192.168.100.75";  
    order_client["staff_id"]         = "1003";  
    order_client["terminal_type"]    = 2;  
    Json::Value request_content;     // 构造 request_content  
    request_content["pay_mch_key"]   = pay_mch_key;  
    request_content["pay_content"]   = pay_content;  
    request_content["order_client"]  = order_client;  
    request_content["nonce_str"]     = "416492026bc84091bcaf7e74ea90ceba";  
    Json::FastWriter w;  
    std::string request_content_str = w.write(request_content);  
    /* 2. 根据上面的业务请求参数计算认证码 */  
    Json::Value authen;  
    std::string hmac;  
    calc_HMAC_SHA256(authen_key, request_content_str, &hmac); //计算认证码  
    authen["authen_code"] = hmac;  
    authen["authen_type"] = 1; //hmac_sha256 为1  
    Json::Value authen_info;  
    authen_info["a"] = authen;  //认证码  
    /* 3. 拼装最终请求参数 */  
    Json::Value request;       //构造最终发给服务器的请求  
    request["request_content"] = request_content_str;  
    request["authen_info"]     = authen_info;  
    std::string request_str = w.write(request);  
    return request_str;  
}  

计算认证码:

/* 
返回是否成功,成功时认证码存放于 hmac 指向的 string 
*/  
bool calc_HMAC_SHA256(const std::string &key, const std::string &input, std::string *hmac)  
{  
    unsigned char md[SHA256_DIGEST_LENGTH] = {0};//32 bytes  
    char format_md[65] = {0};  
    unsigned int md_len = sizeof(md);  
    HMAC_CTX ctx;  
    HMAC_CTX_init(&ctx);  
    if (!HMAC_Init_ex(&ctx, key.data(), (int)key.length(), EVP_sha256(), NULL)  ||  
        !HMAC_Update(&ctx, (const unsigned char *)input.data(), input.length()) ||  
        !HMAC_Final(&ctx, md, &md_len)) {  
        HMAC_CTX_cleanup(&ctx);  
        return false;  
    }  
    HMAC_CTX_cleanup(&ctx);  
    for (int i = 0; i < 32; i++) {  
        snprintf(&format_md[i * 2], 3, "%02x", md[i]); //二进制转为十六进制大写  
    }  
    hmac->assign(format_md);  
    // 转大写  
    transform(hmac->begin(), hmac->end(), hmac->begin(), ::toupper);  
    return true;  
}