Files
kami_gateway/docs/api.md
danial e88ff05a14 refactor(trace): 重命名 otel 包为 otelTrace并更新相关引用
- 将内部使用的 otel 包重命名为 otelTrace
- 更新了所有引用该包的文件中的导入路径
- 修改了部分函数和变量名称以适应新的包名
2025-02-23 21:56:29 +08:00

13 KiB
Raw Blame History

对接文档

PayKey{{.payKey}}
AppSecret:{{.paySecret}}

请求支付页面

请求卡密支付页面,页面如下:
img.png

请求参数

地址http(s)://{{.shopHost}}/?sign=xxx 方法GET

参数名称 类型 是否必须 描述 示例
sign string 签名 6634ddd39796e4e0a98d6f5e919ae50ddc82edbf255f15aa2e30c5c70381e7b9648
returnUrl string 返回地址 订单完成(成功或失败)后的返回地址

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() string {
	r, err := json.Marshal(p)
	if err != nil {
		return ""
	}
	return string(r)
}

func Encrypt(p *OrderParams) string {
	prepareData := String()

	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)
}

请求实际支付金额(可选)

通过面额获取实际支付金额。注意,实际支付面额可能会随时修改,建议每次拉取订单前重新获取最新面额,切勿缓存。 当前接口会返回当前面额在各个平台设置的实际支付金额,以及设置各个平台的链接,根据需要获取。

接口http(s)://{{.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 需要下单的链接

请求订单(创建订单)

接口http(s)://{{.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

参数说明

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 附带返回信息 成功

查询订单

地址http(s)://{{.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 订单状态 successfail, wait
faceVal float 面额
amount string 实际面额

签名算法sign

注意:
1 对参数进行签名时,一定不要写死!!!,请按签名算法进行计算!!
2 所有提交参数都需要参与签名计算 为空的也需要

参数签名算法示例算法

请注意: 1.对参数进行签名时,一定不要写死!!!,请按签名算法进行计算!! 2.所有提交参数都需要参与签名计算 为空的也需要 3.下面的参数只是示例,具体参数要根据实际接口参数进行验签

Golang 算法

package main

import (
	"crypto/md5"
	"encoding/hex"
	"sort"
	"strconv"
	"time"
)

func main() {
	//实际获取的appKey值
	appKey := "1f2811dcd32b2c5c"
	//实际获取的appSecret值
	appSecret := "3C569A210D1260B2"

	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
}

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&param2=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
tradeStatus string 交易状态 success
statusCode string 订单状态 success

签名算法

签名算法参见请求订单(创建订单)接口 ↑