17 KiB
对接文档
AppKey:{{.payKey}}
AppSecret:{{.paySecret}}
1.请求支付页面
1.DEMO文件链接Python demo文件
请求参数
地址:{{.shopHost}}/?sign=xxx
方法:GET
| 参数名称 | 类型 | 是否必须 | 描述 | 示例 |
|---|---|---|---|---|
| sign | string | 是 | 签名 | 6634ddd39796e4e0a98d6f5e919ae50ddc82edbf255f15aa2e30c5c70381e7b9648 |
| returnUrl | string | 否 | 返回地址 | 订单完成(成功或失败)后的返回地址 https://baidu.com/notify |
sign生成算法
注意:生成签名时,需要提前按照参数的参数名进行排序,按照 a-z 顺序排序
| 参数名称 | 类型 | 是否必须 | 描述 | 示例 |
|---|---|---|---|---|
| payKey | string | 是 | 支付 key | 20190520123456789 |
| generatedTime | number | 是 | 支付时间 | 默认为 10 位当前时间(单位/秒) |
| duration | number | 是 | 订单存续时间 | 默认为 24 小时 |
| orderNo | string | 是 | 订单号(自定义生成) | 20190520123456789 |
| notifyUrl | string | 是 | 回调地址 | https://baidu.com/notify |
| showMMValue | string | 是 | 卡片面额 | 100 |
| productCode | string | 是 | 卡片编码 | 苹果卡 |
通道编码
通道编码需参考后台配置,以下仅作为示例
| 通道 | 编码 | 说明 |
|---|---|---|
| 苹果充值卡 | 8545 | 苹果充值卡面,由卡号和卡密组成 |
| 沃尔玛充值卡 | 8645 | 沃尔玛充值卡面,有卡号和卡密组成 |
| 天猫店铺充值兑换|确认收货版 | 8745 | 天猫店铺充值,用户秒收货秒回调 |
| 天猫店铺充值兑换|好评版 | 8645 | 天猫店铺充值,用户秒好评秒回调 |
加密算法
需要将上述参数加密生成 sign 参数,sign 参数需要拼接在 url
后面,如:http://121.37.253.228:12305/?sign=6634ddd39796e4e0a98d6f5e919ae50ddc82edbf255f15aa2e30c5c70381e7b96489f102aa574e70a4ea1b874685dfafec957b237b02d5980f0a22139d860c7d7a8d5c58e3dfbde606a0de08186a4d45228bcc1917a35768f1903bee921b78b118e8b31d25642737cb3e094c140c81f7&showMM=100&linkID=736797719398。
sign 加密算法为 AES/CBC 加密,数据填充模式为 PKCS7 填充,加密 key 和 iv 如下:
key = thisis32bitlongpassphraseimusing
iv = 1234567890123456
加密算法参考
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/hex"
"encoding/json"
"fmt"
)
type OrderParams struct {
OrderNo string `json:"orderNo"`
PayKey string `json:"payKey"` // 支付明文秘钥
NotifyUrl string `json:"notifyUrl"` // 回调地址
GeneratedTime int64 `json:"generatedTime"` // 过期时间
Duration int `json:"duration"` // 存续时间(小时)
ProductCode string `json:"productCode"`
ShowMMValue float64 `json:"showMMValue"`
}
func String(p *OrderParams) string {
r, err := json.Marshal(p)
if err != nil {
return ""
}
logs.Info(string(r))
return string(r)
}
func Encrypt(p *OrderParams) string {
prepareData := String(p)
print(prepareData, "\n")
if prepareData == "" {
return prepareData
}
// 加密密码数据
key := "thisis32bitlongpassphraseimusing"
iv := "1234567890123456"
result, _ := AesCBCEncrypt([]byte(prepareData), []byte(key), []byte(iv))
return hex.EncodeToString(result)
}
// AesCBCEncrypt AES/CBC/PKCS7Padding 加密
func AesCBCEncrypt(plaintext []byte, key []byte, iv []byte) ([]byte, error) {
// AES
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// PKCS7 填充
plaintext = paddingPKCS7(plaintext, aes.BlockSize)
// CBC 加密
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(plaintext, plaintext)
return plaintext, nil
}
// PKCS7 填充
func paddingPKCS7(plaintext []byte, blockSize int) []byte {
paddingSize := blockSize - len(plaintext)%blockSize
paddingText := bytes.Repeat([]byte{byte(paddingSize)}, paddingSize)
return append(plaintext, paddingText...)
}
func main() {
orderParams := OrderParams{
OrderNo: "20190520123456789",
PayKey: "20190520123456789",
NotifyUrl: "https://baidu.com/notify",
GeneratedTime: 1558312000,
Duration: 24,
ProductCode: "8645",
ShowMMValue: 100,
}
sign := Encrypt(&orderParams)
// 原始本文
fmt.Println(sign)
}
// 原始文本:{"orderNo":"20190520123456789","payKey":"20190520123456789","notifyUrl":"https://baidu.com/notify","generatedTime":1558312000,"duration":24,"productCode":"8645","showMMValue":100}
// aes加密后的文本:94db297041a61fa78ac2176b9e8e1e9b34d2ae33b6d46fc8c731a34b4c2b76eea7738993c2c175e6d61648c31c00b5d6d465246aa39b5fba5d6b77599f112c791370486b9fb19ad675e228b1d36ec6ad890ac692a262a73f126dda2bffae493452ea20d8604874af1ff2ba67cf6aab5c5821d100beec4d4c4de86d4c014fc8fe0bfe61b259752007f498dbee92f0136b2cbb756ff5405f95fc7763405022c835812f58dda86c9d72f84c6d576d2e98909d0e499e3c4b4da552f478bfbce3ba63
// 签名:key=thisis32bitlongpassphraseimusing iv=1234567890123456
// 算法:CBC非对称加密/PKCS7填充
2.请求实际支付金额(可选)
通过面额获取实际支付金额。注意,实际支付面额可能会随时修改,建议每次拉取订单前重新获取最新面额,切勿缓存。
当前接口会返回当前面额在各个平台设置的实际支付金额,以及设置各个平台的链接,根据需要获取。
接口:{{.remoteHost}}/gateway/getAllowedMM
请求方式:GET
| 参数名称 | 类型 | 是否必须 | 描述 | 实例 |
|---|---|---|---|---|
| showMMValue | string | 是 | 展示面额 | 充值卡上的面额 |
| payKey | string | 是 | 支付 key | 20190520123456789 |
| productCode | string | 卡片编码 | 是 | 8456 |
返回参数
| 参数名称 | 参数类型 | 描述 | 说明 |
|---|---|---|---|
| code | int | 平台参数 | 0 成功 其他失败 |
| msg | string | 信息提示 | 错误原因 |
| data | interface | 具体返回数据 | 返回数据如下 |
具体成功返回数据
| 参数名称 | 参数类型 | 描述 | 说明 |
|---|---|---|---|
| showLabel | string | 卡面面值 | |
| factLabel | string | 实际面值 | |
| linkID | string | 需要下单的链接 |
3.提交订单(创建订单)
提交订单接口,此接口用于第三方直接提交卡号/卡密,使用自有拉单页面
接口:{{.remoteHost}}/gateway/scan
请求方式:POST
请求参数
| 参数名称 | 类型 | 是否必须 | 描述 | 示例 |
|---|---|---|---|---|
| exValue | string | 是 | 扩展参数 | 卡密数据(具体格式如下) |
| orderNo | string | 是 | 订单号 | 20190520123456789 |
| orderPeriod | int | 否 | 订单有效期(小时) | 24 |
| orderPrice | float | 是 | 订单价格 | 100.12 |
| notifyUrl | string | 是 | 回调地址 | https://baidu.com/notify?sign=xxx |
| payKey | string | 是 | 商户秘钥 | |
| timestamp | int | 是 | 时间戳 | Unix 时间戳,时区为 GMT+8 允许与服务器最大误差 30 秒 |
| sign | string | 是 | 签名 | 签名算法如下 |
| productCode | string | 卡片编码 | 是 | 8456 |
| ip | string | 否 | 客户端IP | 127.0.0.1 |
| deviceId | string | 否 | 设备唯一标识 | 127.0.0.1 |
参数说明
exValue
内需参数
| 参数名称 | 参数类型 | 描述 | 说明 |
|---|---|---|---|
| data | string | 卡密 | --- |
| cardNo | string | 面额 | --- |
| recoveryType | string | 回收类型 | 2.仅有卡密 8.卡密/卡号 |
返回参数
返回参数
| 参数名称 | 参数类型 | 描述 | 说明 |
|---|---|---|---|
| code | int | 平台参数 | 0 成功 其他失败 |
| msg | string | 信息提示 | |
| data | interface | 具体返回数据 | 返回数据如下 |
具体成功返回数据
| 参数名称 | 类型 | 是否必须 | 描述 | 示例 |
|---|---|---|---|---|
| statusCode | string | 是 | 返回状态码 | 00 成功,其他失败 |
| orderNo | string | 是 | 订单号 | 20190520123456789 |
| orderPrice | string | 是 | 订单价格 | 100.12 |
| sign | string | 是 | 签名 | xxx |
| msg | string | 是 | 附带返回信息 | 成功 |
4.查询订单
地址:{{.remoteHost}}/gateway/merchant/query 方法:Get
查询参数
| 参数名称 | 参数类型 | 是否必须 | 描述 | 说明 |
|---|---|---|---|---|
| orderNo | string | 是 | 订单号 | |
| appKey | string | 是 | 应用 key | |
| timestamp | int | 是 | 时间戳 | Unix 时间戳,时区为 GMT+8 允许与服务器最大误差 30 秒 |
| sign | string | 是 | 签名 | xxx |
返回参数
| 参数名称 | 参数类型 | 描述 | 说明 |
|---|---|---|---|
| code | int | 平台参数 | 0 成功 其他失败 |
| msg | string | 信息提示 | |
| data | interface | 具体返回数据 | 返回数据如下 |
具体成功返回数据
| 参数名称 | 参数类型 | 描述 | 说明 |
|---|---|---|---|
| orderNo | string | 订单号 | |
| cardNo | string | 卡号 | |
| cardPwd | string | 卡密 | |
| status | string | 订单状态 | success,fail, wait |
| faceVal | float | 面额 | |
| amount | string | 实际面额 | |
| CardReturnData | string | 充值失败原因(明细) |
4.创建订单(新)
创建订单,并返回下单单号,地址等信息
地址:{{.remoteHost}}/gateway/createOrder
请求参数
| 参数名称 | 类型 | 是否必须 | 描述 | 示例 |
|---|---|---|---|---|
| orderNo | string | 是 | 订单号 | 20190520123456789 |
| orderPeriod | int | 否 | 订单有效期(小时) | 24 |
| orderPrice | float | 是 | 订单价格 | 100.12 |
| notifyUrl | string | 是 | 回调地址 | https://baidu.com/notify?sign=xxx |
| payKey | string | 是 | 商户秘钥 | |
| timestamp | int | 是 | 时间戳 | Unix 时间戳,时区为 GMT+8 允许与服务器最大误差 30 秒 |
| sign | string | 是 | 签名 | 签名算法如下 |
| productCode | string | 卡片编码 | 是 | 8456 |
返回参数
| 参数名称 | 参数类型 | 描述 | 说明 |
|---|---|---|---|
| code | int | 平台参数 | 0 成功 -1失败 |
| msg | string | 信息提示 | 失败的具体原因 |
| data | interface | 具体返回数据 | 返回数据如下 |
具体成功返回数据
| 参数名称 | 参数类型 | 描述 | 说明 |
|---|---|---|---|
| productCode | string | 产品编码 | |
| paymentName | string | 产品名称 | |
| transactionType | string | 卡密 | 是兑换还是充值 暂时无用 |
| payUrl | string | 支付链接 | 最终构建的支付链接 |
| merchantOrderNo | string | 商户订单号 | 来源自请求传入订单号 |
| orderNo | string | 订单编号 | 系统编号 |
签名算法(sign)
注意:
1 对参数进行签名时,一定不要写死!!!,请按签名算法进行计算!!
2 所有提交参数都需要参与签名计算 为空的也需要
参数签名算法示例算法
请注意: 1.对参数进行签名时,一定不要写死!!!,请按签名算法进行计算!! 2.所有提交参数都需要参与签名计算 为空的也需要3.下面的参数只是示例,具体参数要根据实际接口参数进行验签
package main
import (
"crypto/md5"
"encoding/hex"
"sort"
"strconv"
"time"
)
func main() {
//实际获取的appKey值
appKey := "1f2811dcd32b2c5c"
//实际获取的appSecret值
appSecret := "3C569A210D1260B2"
// 如果有其它参数,依次添加 key=value
params := map[string]string{}
params["appKey"] = appKey
params["phone"] = "13800138000"
params["timestamp"] = strconv.FormatInt(time.Now().Unix(), 10)
params["amount"] = "100"
strArr := SortMap(params)
signStr := ""
for i := 0; i < len(strArr); i++ {
k := strArr[i]
if len(params[k]) == 0 {
signStr += k
} else {
signStr += k + params[k]
}
}
signStr += appSecret
h := md5.New()
h.Write([]byte(signStr))
hex.EncodeToString(h.Sum(nil))
}
// SortMap 对map的key值进行排序
func SortMap(m map[string]string) []string {
var arr []string
for k := range m {
arr = append(arr, k)
}
sort.Strings(arr)
return arr
}
// 原始值
// {
// "amount": "100",
// "appKey": "1f2811dcd32b2c5c",
// "phone": "13800138000",
// "timestamp": "1737284505"
// }
// appSecret:3C569A210D1260B2
// 加密前的值
// amount100appKey1f2811dcd32b2c5cphone13800138000timestamp17372845053C569A210D1260B2
// 加密后的值:96ff597f7b89322e83e234e3ad1d42e5
Java 算法
String appSecret = "3C569A210D1260B2";
TreeMap<String, String> params = new TreeMap<String,String>();
params.put("timestamp", ""+(System.currentTimeMillis()/1000L));
params.put("phone", "13800138000");
params.put("amount", "100");
StringBuilder sb = new StringBuilder();
for(Entry<String, String> item : params.entrySet()){
if(item.getKey().equals("sign"))
continue;
sb.append(item.getKey()).append(item.getValue());
}
sb.append(appSecret);
params.put("sign",md5(sb.toString()));
订单回调接口签名检验
回调接口示例
地址:http://baidu.com/notify?param1=xx¶m2=xx
方法:Get
返回参数:
| 参数名称 | 参数类型 | 含义 | 示例 |
|---|---|---|---|
| orderNo | string | 订单号(己方账号) | 20190520123456789 |
| orderPrice | string | 订单价格(面值,一般为整数) | 100 |
| factPrice | string | 实际价格 | 98.89 |
| orderTime | string | 回调时间 | 2006010215:04:05 |
| trxNo | string | 交易(系统账户)流水号 | 20190520123456789 |
| payKey | string | 支付通道 key | 20190520123456789 |
| sign | string | 签名 | xxx |
| statusCode | int | 交易状态 | 1 成功,0 通用失败 其他状态码待添加 |
| failReason | string | 订单状态 | 失败的具体原因 |
签名算法
签名算法参见提交订单(创建订单)接口 ↑
