logo

搜索...

⌘ K

中文

产品文档
接口文档
资源下载
帮助中心

开始使用

总体概览

场景能力

接入步骤

收款能力

CKP 集成收银台页面

交互示意

集成准备

集成步骤

Deeplink 直跳方式

交互示意

集成准备

集成步骤

QRCode 展示二维码

交互示意

集成准备

集成步骤

付款能力

能力概述

充值入金

发起 U 提现/付款

发起法币提现

接收付款结果

支持的链和币种

支持的链

支持的币种

附录

钱包/币种/链

交易状态枚举值

支付状态

退款状态

提现状态

批量提现状态

错误码说明

签名算法

签名算法

算法描述

参与签名的字段:

  • apiPath:请求 URI 的 path 部分(必须),不含 host、不含 query string,也不含 /crypto-payment 前缀,如 /payin/v1/createPayment
  • body:请求体的原始 JSON 字符串(必须),与发送给 Paydify 的 body 完全一致
  • x-api-key:同 appId(必须)
  • x-api-timestamp:当前时间戳,单位毫秒(必须)

注意:URL 中的 query string 参数不参与签名,请确保签名内容只包含上述 4 个字段。因此请勿通过 query string 传递敏感业务参数,敏感参数应置于已签名的请求体 body 中。

按照以下步骤实现:

  1. 将以上 4 个字段的名称和值放入 contentMap,按 key 字典序升序排序
  2. 对 contentMap 进行 JSON 序列化,得到 content 字符串
  3. 使用 HMAC-SHA256 算法对 content 字符串以 apiSecret 作为密钥计算签名
  4. 对签名结果做 Base64 编码,得到最终的签名字符串

如以下示例:

curl -H 'x-api-key: key' \
     -H 'x-api-timestamp: 1744636844000' \
     -H 'x-api-signature: 0xb7Kxxxx=' \
      'https://{HOST}/path/to/pay' \
      -d '{"data":"test"}'

排序后 JSON 序列化的 contentMap 如下(注意 body 是原始字符串而不是对象):

{
  "apiPath": "/path/to/pay",
  "body": "{\"data\":\"test\"}",
  "x-api-key": "key",
  "x-api-timestamp": "1744636844000"
}

对这个 JSON 字符串以 apiSecret 为密钥做 HMAC-SHA256,再 Base64 编码,即为签名值。

代码实现

后端实现示例

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "net/url"
    "sort"
)

func GenSign(appId, apiSecret, pathUrl, payload string, tm int64) string {
	// 解析 URL
	path := ""
	contentMap := make(map[string]string)
	if u, err := url.Parse(pathUrl); err == nil {
		path = u.Path
		for k, v := range u.Query() {
			if len(v) > 0 {
				contentMap[k] = v[0]
			}
		}
	}

	// 构建待签名的 map
	contentMap["x-api-key"] = appId
	contentMap["x-api-timestamp"] = fmt.Sprintf("%d", tm) // 毫秒
	contentMap["apiPath"] = path
	contentMap["body"] = payload

	// 获取所有 keys 并排序
	keys := make([]string, 0, len(contentMap))
	for k := range contentMap {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	// 创建有序的 map
	orderedMap := make(map[string]string)
	for _, k := range keys {
		orderedMap[k] = contentMap[k]
	}

	// JSON 序列化
	content, _ := json.Marshal(orderedMap)

	// 计算 HMAC
	mac := hmac.New(sha256.New, []byte(apiSecret))
	mac.Write(content)
	return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}

// 使用示例
GenSign("A123456", "ABC123", "/path/to/pay?param1=test1&param2=test2", "{"data":"test"}", time.Now().UnixMilli())

Postman Pre-request Script

用于在 Postman 中自动生成 Payin / Payout 签名,将以下脚本粘贴到 Pre-request Script 标签页:

const appId = 'YOUR_APP_ID';
const apiSecret = 'YOUR_API_SECRET';

const ts = Date.now();

pm.request.headers.upsert({ key: 'x-api-key', value: appId });
pm.request.headers.upsert({ key: 'x-api-timestamp', value: String(ts) });

const path = pm.request.url.getPath();
const rawBody =
  pm.request.body && pm.request.body.raw ? pm.request.body.raw : '';
const bodyForSign = rawBody.replace(/\r?\n/g, '');

const ordered = {
  apiPath: path,
  body: bodyForSign,
  'x-api-key': appId,
  'x-api-timestamp': String(ts),
};

const content = JSON.stringify(ordered);

console.log('Signature content:', ordered);

const signature = CryptoJS.HmacSHA256(content, apiSecret).toString(
  CryptoJS.enc.Base64
);

pm.request.headers.upsert({ key: 'x-api-signature', value: signature });

console.log('Generated signature:', signature);

扫码付(QR Pay)与融合接口(Fusion Pay)走 X-DAPI-* 请求头,签名规则不同,详见 扫码付签名算法。

目录