1. 认证方式
使用API Key进行认证时,需要在请求头中添加以下信息:
Authorization: ApiKey {api_key}
Signature: {signature}
其中:
-
Authorization
:API Key认证头,格式为
ApiKey {api_key}
-
Signature
:请求签名(必填),用于验证请求数据的完整性
2. 签名验证
签名用于验证请求数据的完整性,防止数据被篡改。签名生成步骤:
-
过滤请求参数:排除
sign
参数、
null
值、空字符串、空数组、空对象
- 将过滤后的参数按参数名ASCII码升序排序
-
对字典或列表类型的值进行JSON序列化(
sort_keys=true
,
separators=(',', ':')
)
-
对每个参数值进行URL编码(
UTF-8
编码)
-
将排序后的参数拼接为字符串:
key1=value1&key2=value2
- 使用API Secret作为密钥,通过HMAC-SHA256算法生成签名
-
将签名添加到请求头
Signature
中
2.1 签名计算示例
# 原始请求数据
{
"account_book_id": "123456",
"amount": "100.00",
"payee_info": {
"identity_type": "ALIPAY_ACCOUNT",
"name": "张三",
"identity": "zhangsan@example.com"
},
"sign": "不需要参与签名",
"empty_param": "",
"null_param": null
}
# 1. 过滤后(排除sign、空字符串、null)
{
"account_book_id": "123456",
"amount": "100.00",
"payee_info": {
"identity_type": "ALIPAY_ACCOUNT",
"name": "张三",
"identity": "zhangsan@example.com"
}
}
# 2. 按参数名升序排序
account_book_id, amount, payee_info
# 3. JSON序列化嵌套对象
payee_info={"identity":"zhangsan@example.com","identity_type":"ALIPAY_ACCOUNT","name":"张三"}
# 4. URL编码(处理中文)
name=%E5%BC%A0%E4%B8%89
# 5. 拼接字符串
account_book_id=123456&amount=100.0&payee_info=%7B%22identity%22%3A%22zhangsan%40example.com%22%2C%22identity_type%22%3A%22ALIPAY_ACCOUNT%22%2C%22name%22%3A%22%E5%BC%A0%E4%B8%89%22%7D
# 6. HMAC-SHA256签名(密钥为API Secret)
signature = HMAC-SHA256(api_secret, sign_str)
# 7. 请求头中添加签名
Signature: {signature}
3. 注意事项
- API Key和Secret请妥善保管,不要泄露给他人
-
签名验证是
必填
的,未带签名或签名错误将返回401
- 签名使用HMAC-SHA256算法,密钥为API Secret
-
签名计算前会自动过滤:
sign
参数、
null
值、空字符串、空数组、空对象
-
嵌套对象(如
payee_info
)会先进行JSON序列化再参与签名
- 参数值会进行URL编码(UTF-8),确保中文字符正确处理
- 定期更新API Key,建议每3-6个月更换一次
- 如发现API Key泄露,请立即禁用并重新生成
- API Key有过期时间,请在过期前及时更新
4. 发起转账
4.1 接口说明
从资金账户转账到支付宝账户/银行卡
API接口地址
POST https://api.qcsj88888.com/payment/openapi/account/transfer
请求参数
| 参数名 |
类型 |
是否必填 |
描述 |
| account_book_id |
string |
是 |
付款方资金账户号 |
| amount |
string |
是 |
转账金额,单位为元,精确到小数点后两位,大于0.02元 |
| order_title |
string |
否 |
转账标题 |
| remark |
string |
否 |
转账备注 |
| third_biz_no |
string |
是 |
三方订单号(商户侧唯一标识,不可重复) |
| payee_info |
object |
是 |
{{ expandedSections.payee_info ? "▼" : "▶" }} 收款方信息
| 参数名 |
类型 |
是否必填 |
描述 |
| identity_type |
string |
是 |
收款方类型:alipay(支付宝账户)/ bank(银行卡) |
| name |
string |
是 |
收款方真实姓名 |
| identity |
string |
是 |
收款方唯一标识(支付宝账号/银行卡号) |
| bankcard_ext_info |
object |
否 |
{{ expandedSections.bankcard_ext_info ? "▼" : "▶" }}
银行卡信息(当 identity_type 为 bank 时必填)
| 参数名 |
类型 |
是否必填 |
描述 |
| account_type |
string |
是 |
收款账户类型: 1/2。对公: 1,对私: 2 |
| inst_name |
string |
否 |
机构名称(当 account_type 是 1 时必填) |
| inst_province |
string |
否 |
银行所在省份 |
| inst_city |
string |
否 |
收款银行所在市 |
| inst_branch_name |
string |
否 |
收款银行所属支行 |
| bank_code |
string |
否 |
银行支行联行号 |
|
|
请求示例
curl -X POST 'https://api.qcsj88888.com/payment/openapi/account/transfer' \
-H 'Authorization: ApiKey your_api_key' \
-H 'Signature: your_signature' \
-H 'Content-Type: application/json' \
-d '{
"account_book_id": "资金账号",
"amount": "100.00",
"order_title": "转账标题",
"third_biz_no": "商户订单号202604270001",
"payee_info": {
"identity_type": "ALIPAY_ACCOUNT",
"name": "收款人姓名",
"identity": "收款人支付宝账号"
}
}'
响应示例
{"code": 200, "message": "转账申请已提交", "data": {"status": "DEALING", "order_no": "2026042711122334455", "third_biz_no": "商户订单号202604270001"}}
5. 查询转账
5.1 接口说明
根据三方订单号查询转账状态和详情
API接口地址
POST https://api.qcsj88888.com/payment/openapi/account/transfer/query
请求参数
| 参数名 |
类型 |
是否必填 |
描述 |
| third_biz_no |
string |
是 |
三方订单号(发起转账时传入的商户侧唯一标识) |
请求示例
curl -X POST 'https://api.qcsj88888.com/payment/openapi/account/transfer/query' \
-H 'Authorization: ApiKey your_api_key' \
-H 'Signature: your_signature' \
-H 'Content-Type: application/json' \
-d '{
"third_biz_no": "商户订单号202604270001"
}'
响应示例
{
"code": 200,
"message": "查询成功",
"data": {
"status": "SUCCESS",
"order_no": "2026042711122334455",
"amount": "100.00",
"payee_info": {
"identity_type": "ALIPAY_ACCOUNT",
"name": "张*",
"identity": "z****@example.com"
},
"created_time": "2026-04-27 11:22:33",
"updated_time": "2026-04-27 11:25:45"
}
}
状态说明
| 状态码 |
描述 |
| DEALING |
处理中 |
| SUCCESS |
成功 |
| FAIL |
失败 |
| REFUND |
已退款 |
6. 账户余额
6.1 接口说明
查询指定企业资金专户的余额信息
API接口地址
POST https://api.qcsj88888.com/payment/openapi/account/balance/query
请求参数
| 参数名 |
类型 |
是否必填 |
描述 |
| enterprise_id |
string |
是 |
企业ID |
请求示例
curl -X POST 'https://api.qcsj88888.com/payment/openapi/account/balance/query' \
-H 'Authorization: ApiKey your_api_key' \
-H 'Signature: your_signature' \
-H 'Content-Type: application/json' \
-d '{
"enterprise_id": "2088480777900000"
}'
响应示例
{
"code": 200,
"message": "查询成功",
"data": [
{
"account_book_id": "2088480770900000",
"available_amount": "50000.00",
"enable_status": "ENABLE",
"scene": "B2B_TRANS",
"account_card_info": {
"card_no": "xxxx",
"bank_name": "招商银行"
}
}
]
}
响应字段说明
| 字段名 |
类型 |
描述 |
| account_book_id |
string |
资金专户号 |
| available_amount |
string |
可用余额(单位:元,精确到小数点后两位) |
| enable_status |
string |
启用状态:ENABLE(启用)/ DISABLE(禁用) |
| scene |
string |
场景类型:B2B_TRANS(B2B转账) |
| account_card_info |
object |
账户卡信息(银行卡号、银行名称等) |
注意事项
-
返回结果为
数组
,一个企业可能有多个资金专户
-
余额单位为
元
,精确到小数点后两位
-
仅返回
scene
为
B2B_TRANS
的资金专户
7. 回调通知
7.1 接口说明
当转账状态发生变化时,系统会主动向商户配置的回调地址发送通知。
回调地址配置
系统按照以下优先级获取回调地址:
-
API Key 级别
:在创建/编辑 API Key 时配置回调地址(优先级最高)
-
开放平台配置
:在
应用配置
页面设置默认回调地址
说明:如果 API Key 已配置回调地址,则优先使用;否则使用开放平台配置中的回调地址。
通知方式
-
POST 请求
:系统通过 HTTP POST 方式将通知数据发送到商户的回调地址
-
表单形式
:通知参数以表单形式提交(Content-Type: multipart/form-data)
-
重试机制
:如果通知失败,系统会自动重试(最多2次,间隔1秒、2秒)
请求参数
| 参数名 |
类型 |
描述 |
| notify_id |
string |
通知ID,唯一标识 |
| timestamp |
int |
通知时间戳(毫秒) |
| content |
string |
JSON格式的通知内容 |
content 字段说明
| 参数名 |
类型 |
描述 |
| status |
string |
转账状态:SUCCESS(成功)、FAIL(失败) |
| order_no |
string |
平台订单号 |
| third_biz_no |
string |
商户订单号(发起转账时传入的三方订单号) |
| amount |
number |
转账金额(元) |
| created_time |
string |
创建时间 |
| updated_time |
string |
更新时间 |
通知示例
成功示例
POST /your/callback/url HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="notify_id"
n1234567890123456789
------WebKitFormBoundary
Content-Disposition: form-data; name="timestamp"
1715767200000
------WebKitFormBoundary
Content-Disposition: form-data; name="content"
{
"status": "SUCCESS",
"order_no": "2026042711122334455",
"third_biz_no": "商户订单号202604270001",
"amount": "100.00",
"created_time": "2026-04-27 11:22:33",
"updated_time": "2026-04-27 11:25:45"
}
------WebKitFormBoundary--
转账成功示例
POST /商户回调地址 HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="notify_id"
n12535554089713704963
------WebKitFormBoundary
Content-Disposition: form-data; name="timestamp"
1779037365774
------WebKitFormBoundary
Content-Disposition: form-data; name="content"
{
"status": "SUCCESS",
"order_no": "2026042711122334455",
"third_biz_no": "商户订单号202604270001",
"amount": "100.00",
"out_biz_no": "12535474352010076162",
"enterprise_id": "2088480767913636",
"account_book_id": "2088480770941200",
"order_title": "转账标题",
"created_time": "2026-04-27 11:22:33"
}
------WebKitFormBoundary--
转账失败示例
POST /your/callback/url HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="notify_id"
n12535554089713704963
------WebKitFormBoundary
Content-Disposition: form-data; name="timestamp"
1779037365774
------WebKitFormBoundary
Content-Disposition: form-data; name="content"
{
"status": "FAIL",
"third_biz_no": "商户订单号202604270001",
"amount": "1.00",
"error_msg": "收款账号不存在或姓名有误,建议核实账号和姓名是否准确"
}
------WebKitFormBoundary--
------WebKitFormBoundary--
响应要求
商户服务端收到通知后,需要返回 HTTP 200 状态码表示成功接收。如果返回非 200
状态码或超时,系统会进行重试。
注意事项
-
回调地址需要支持
HTTPS
协议
-
确保回调接口能够在
5秒内
返回响应
-
重要
:回调通知不包含签名验证,收到通知后请主动调用查询接口确认订单状态,以确保数据真实性
-
通知可能会重复发送,请确保业务逻辑支持
幂等性
-
系统最多重试
2次
,重试间隔为 1 秒和 2 秒
8. 常见错误
-
401 Invalid API Key
:API Key无效或已过期
-
401 Signature header required
:未提供Signature请求头
-
401 Invalid Signature
:签名验证失败,请检查签名计算方式
-
400 Bad Request
:请求参数错误
-
403 Forbidden
:无权限访问
-
500 Internal Server Error
:服务器内部错误
9. PHP 示例代码
9.1 以下是签名生成的 PHP 示例代码:
<?php
class SignatureGenerator
{
private static function ksortRecursive(&$array) {
if (!is_array($array)) return;
ksort($array, SORT_STRING);
foreach ($array as &$value) {
self::ksortRecursive($value);
}
}
public static function generateSignature(
string $apiSecret,
array $requestData,
array $excludeParams = ['sign']
): string {
$filteredData = [];
foreach ($requestData as $key => $value) {
if (in_array($key, $excludeParams, true)) {
continue;
}
if ($value === null || $value === '') {
continue;
}
if (is_array($value) && empty($value)) {
continue;
}
$filteredData[$key] = $value;
}
self::ksortRecursive($filteredData);
$collect = [];
foreach ($filteredData as $key => $value) {
if (is_array($value)) {
$value = json_encode($value, JSON_UNESCAPED_SLASHES);
}
$encodedValue = rawurlencode((string)$value);
$collect[] = "{$key}={$encodedValue}";
}
$signStr = implode('&', $collect);
return hash_hmac('sha256', $signStr, $apiSecret);
}
public static function verifySignature(
string $apiSecret,
array $requestData,
string $signature
): bool {
$expectedSignature = self::generateSignature($apiSecret, $requestData);
return hash_equals($expectedSignature, $signature);
}
}
// ================= 测试调用 =================
$apiSecret = 'your_api_secret_here';
$requestData = [
"account_book_id" => "2088480770900000",
"amount" => "1.00",
"order_title" => "Apikey转账",
"third_biz_no" => "1234242026042700111",
"payee_info" => [
"identity_type" => "ALIPAY_ACCOUNT",
"name" => "钱先生",
"identity" => "1xx9xx9xxxxx"
]
];
// 生成签名
$signature = SignatureGenerator::generateSignature($apiSecret, $requestData);
echo "生成的签名: {$signature}\n";
// 验证签名
$isValid = SignatureGenerator::verifySignature($apiSecret, $requestData, $signature);
echo "签名验证结果: " . ($isValid ? '有效' : '无效') . "\n";
?>