Payroad跨境支付API文档
1. 概述
1.1 编写目的
目的是约定商户与Payroad收单系统间的业务接口。包括通讯协议、交易接口规范、文件格式、加密和摘要规范。指 导商户开发人员依据本规范开发,并与Payroad收单系统对接。
2. 通讯协议
2.1 协议约定
- 平台与Payroad之间基于HTTPS1.2协议通讯,报文组织形式采用 json 规范。
- 双方的报文都密文形式发送,必须同时将报文的密文、会话密钥密文和签名传输给对方。
- 平台和Payroad双方互为客户端和服务端。根据应用的要求,可以由平台作为客户端主动发起交易请求,Payroad 来做应答。也可以由Payroad主动发起交易请求,平台来做应答,平台在开户时需提前设置接收Payroad的请求地址。
- 客户端提交请求使用POST表单方式 (Content-Type:application/json) 提交,内容采用UTF-8编码。
- 请求和响应均由四个域:merchantNo=平台代码、jsonEnc=报文密文、keyEnc=会话密钥密文、sign=报文签名
3 加密及签名规范
3.1 原则
- 交易报文传输都需要进行加密、签名和校验。
- 无论是请求端还是响应端接收到报文后,都需要进行签名验证,即按照约定算法重新生成签名,然后和收到的签名进 行对比,对比通过后才能进行报文内容的解析,否则报文或文件内容可能出现篡改、部分丢失、伪造的问题。
- 报文加密算法:DES/CBC/PKCS5Padding
- 会话密钥生成:KeyGenerator生成
- 会话密钥加密算法:RSA/ECB/PKCS1Padding
- 签名算法:SHA1withRSA
3.2 RSA密钥对获得
openssl genrsa –out rsa_private_key_2048.pem2048
#生成rsa私钥,以X509编码,指定生成的密钥的位数:2048
openssl pkcs8 –topk8 –in rsa_private_key_2048.pem –out pkcs8_rsa_private_key_2048.pem –nocrypt
#将上一步生成的rsa私钥转换成PKCS#8编码
openssl rsa –in rsa_private_key_2048.pem –out rsa_public_key_2048.pem –pubout
#导出rsa公钥,以X509编码商户需要按上面步骤生成商户的公钥pem发给Payroad,
#或商户直接可以向Payroad索要密钥对的生成脚本,生成商户所需的公私钥。
#Payroad也需要把Payroad生成的对应的公钥pem发给商户。
对于商户来说,需要生成商户自己的RSA密钥对(包含公钥和私钥),其中,私钥合作方自己保留,。 同时公钥提供给Payroad 对于Payroad来说,需要为每个商户生成对应的公私钥对。其中,私钥Payroad自己保留,公钥需要提供给商户。
3.3 报文加密及签名
- 对请求或响应Json报文明文(UTF-8编码. 使用发送方的私钥进行签名(SHA1withRSA. ,并将签名结果转换为HEX字符串,得到sign域。
- 使用KeyGenerator生成器,生成DES加密会话密钥SK;
- 使用SK对Json明文进行加密(DES/CBC/PKCS5Padding. ,并将加密结果转换为HEX字符串,得到jsonEnc 域。
- 使用接收方公钥对会话密钥SK加密(RSA/ECB/PKCS1Padding. ,并将结果转换为HEX字符串,得到keyEnc 域。
3.4 报文解密及验签
- 将keyEnc域转换为二进制byte数组,使用接收方放的私钥对会话密钥,得到明文SK;
- 将jsonEnc与转换为二进制byte数组,使用上一步得到的会话密钥SK解密,得到明文json;
- 使用上一步解密得到的明文、发送方公钥和sign域数据验证签名的有效性。
4 业务接口
本章节描述商户接入Payroad相关业务接口。
M表示必输字段,O表示可选字段
4.1 交易接口
4.1.1 请求参数
1 请求地址
Url: https://{baseUrl}/api/payment
请求示例:
{
"amount": 500,
"cardNo": "5329598104782897",
"currency": "CNY",
"cvv": "184",
"expireMonth": "10",
"expireYear": "2025",
"firstName": "daniel",
"goodsDesc": "test",
"goodsNo": "110",
"goodsPrice": "10",
"goodsQuantity": "2",
"lastName": "gu",
"merchantNo": "8888888",
"merchantOrderNo": "1705741227886",
"orderIp": "127.0.0.1",
"tradeWebsite": "https://www.baidu.com/",
"transType": "S"
}
2 请求参数
名称 | Json标签 | 类型 | 属性 | 取值说明 |
---|---|---|---|---|
商户号 | merchantNo | string(32) | M | 平台分配的唯一商户号 |
商户订单号 | merchantOrderNo | string(32) | M | 商户订单号,商户生成的唯一订单号,不可重复 |
交易币种 | currency | string(3) | M | 交易币种 |
交易金额 | amount | decimal(12,2) | M | 交易金额 |
交易类型 | transType | string(1) | M | S-交易 |
卡号 | cardNo | string(20) | M | 卡号 |
安全码 | cvv | string(6) | M | 交易卡的安全码 |
有效期月份 | expireMonth | string(2) | M | 如:02 |
有效期年份 | expireYear | string(4) | M | 如:2024 |
下单ip | orderIp | string(20) | M | 如:127.0.0.1 |
交易网址 | tradeWebsite | string(100) | O | 商品的交易网址 |
发货人姓 | shippingFirstName | String(50) | O | |
发货人名 | shippingLastName | string(50) | O | |
发货人电话 | shippingPhone | string(20) | O | |
发货人邮编 | shippingPostCode | string(10) | O | |
发货地址 | shippingAddress | string(128) | O | |
发货国家 | shippingCountry | string(2) | O | 国家二字码 |
发货州 | shippingState | string(50) | O | |
发货城市 | shippingCity | string(50) | O | |
账单人姓 | billFirstName | String(50) | O | |
账单人名 | billLastName | string(50) | O | |
账单人电话 | billPhone | string(20) | O | |
账单邮编 | billPostCode | string(10) | O | |
账单地址 | billAddress | string(128) | O | |
账单人国家 | billCountry | string(2) | O | 国家二字码 |
账单人州 | billState | string(50) | O | |
账单城市 | billCity | string(50) | O | |
账单人邮箱 | billEmail | string(128) | O | |
持卡人姓 | firstName | string(50) | O | |
持卡人名 | lastName | string(50) | O | |
商品编号 | goodsNo | string(32) | M | |
商品单价 | goodsPrice | string(10) | M | |
商品币种 | goodsCurrency | string(3) | M | |
商品数量 | goodsQuantity | String(10) | M | |
商品描述 | goodsDesc | `string(200) | M | |
商品图片地址 | pictureUrl | String(100) | O |
返回示例:
{
"merchantNo": "147258",
"merchantOrderNo": "1705743863442",
"message": "processing",
"orderAmount": 500,
"orderCurrency": "CNY",
"platOrderNo": "OM00085634",
"redirectUrl": "https://payroad/verify/",
"status": "02"
}
3 响应参数
名称 | Json标签 | 类型 | 属性 | 取值说明 |
---|---|---|---|---|
商户号 | merchantNo | string(32) | M | 平台分配唯一商户号 |
商户唯一订单号 | merchantOrderNo | string(32) | M | 商户订单号 |
平台订单号 | platOrderNo | string(32) | M | 平台订单号 |
订单状态 | status | string(2) | M | 订单状态 00-成功 01-失败 02-支付中 |
结果码 | resultCode | string(10) | O | 结果码 |
描述 | message | string(100) | O | |
跳转地址 | redirectUrl | string(200) | O | 当status=02,且此值有返回时需要跳转此地址做验证 |
订单金额 | orderAmount | decimal(12,2) | M | |
订单币种 | orderCurrency | string(3) | M |
4.2 退款
4.2.1 退款请求参数
1 请求地址
Url: https://{baseUrl}/api/refund
Method: POST
请求示例:
{
"merchantNo": "888888",
"merchantRefundNo": "1705744463154",
"platOrderNo": "OM00085631",
"refundAmount": 500,
"refundCurrency": "CNY",
"remark": "test"
}
2 请求字段
名称 | Json标签 | 类型 | 属性 | 取值说明 |
---|---|---|---|---|
商户号 | merchantNo | string(32) | M | 平台分配唯一商户号 |
商户退款订单号 | merchantRefundNo | string(32) | M | 商户退款订单号,商户生成的唯一订单号,不可重复 |
平台订单号 | platOrderNo | string(32) | M | 平台订单号(交易返回的参数) |
退款币种 | refundCurrency | string(3) | M | |
退款金额 | refundAmount | decimal(12,2) | M | |
退款原因 | remark | string(255) | M |
返回示例:
{
"merchantNo": "888888",
"merchantRefundNo": "1705745403486",
"platOrderNo": "OM00051892",
"platRefundOrderNo": "RF00000043",
"refundAmount": 50,
"refundCurrency": "USD",
"status": "02"
}
3 响应字段
名称 | Json标签 | 类型 | 属性 | 取值说明 |
---|---|---|---|---|
商户号 | merchantNo | string(32) | M | 平台分配唯一商户号 |
商户退款订单号 | merchantRefundNo | string(32) | M | 商户退款订单号,商户生成的唯一订单号,不可重复 |
平台订单号 | platOrderNo | string(32) | M | 平台订单号(交易返回的参数) |
退款币种 | refundCurrency | string(3) | M | |
退款金额 | refundAmount | decimal(12,2) | M | |
退款状态 | status | string(2) | M | 订单状态 00-退款成功 01-退款失败 02-退款中 03-退款审核中 |
平台退款订单号 | platRefundOrderNo | string(32) | M | 平台生成的退款唯一标识(查询时输入) |
结果码 | resultCode | string(10) | O | |
描述 | message | string(100) | O |
4.3 查询
4.3.1 查询请求参数
1 请求地址
Url: https://{baseUrl}/api/query
Method: POST
请求示例:
{
"merchantNo":"20220725006",
"transType":"S",
"flowNo":"OM00051892"
}
2 请求字段
名称 | Json标签 | 类型 | 属性 | 取值说明 |
---|---|---|---|---|
商户号 | merchantNo | string(32) | M | 平台分配唯一商户号 |
交易类型 | transType | string(1) | M | S-交易 R-退款 |
业务流水号 | flowNo | string(32) | M | 交易类型时传交易接口返回的platOrderNo,退款时传返回的platRefundOrderNo |
返回示例:
{
"merchantNo": "888888",
"flowNo": "OM00051892",
"transType": "S",
"status": "00",
"amount": 50,
"currency": "USD"
}
3 响应字段
名称 | Json标签 | 类型 | 属性 | 取值说明 |
---|---|---|---|---|
商户号 | merchantNo | string(32) | M | 平台分配唯一商户号 |
业务流水号 | flowNo | string(32) | M | |
交易类型 | transType | string(1) | M | |
订单状态 | status | string(2) | M | 00-成功 01-失败 02-处理中 |
金额 | amount | decimal(12,2) | M | |
币种 | currency | string(3) | M |
4.4 异步通知
4.4.1 异步通知参数
1 通知地址
商户提供接受异步通知的地址
Method: POST
请求示例:
{
"merchantNo": "888888",
"flowNo": "OM00051892",
"transType": "S",
"status": "00",
"amount": 50,
"currency": "USD"
}
2 请求字段
名称 | Json标签 | 类型 | 属性 | 取值说明 |
---|---|---|---|---|
商户号 | merchantNo | string(32) | M | 平台分配唯一商户号 |
业务流水号 | flowNo | string(32) | M | |
交易类型 | transType | string(1) | M | |
订单状态 | status | string(2) | M | 00-成功 01-失败 02-处理中 |
金额 | amount | decimal(12,2) | M | |
币种 | currency | string(3) | M |
4.4.2 重定向地址
1 通知地址
商户提供接受重定向通知的地址,此地址时交易发生验证时,持卡人在页面验证后跳转的地址
Method: GET
请求示例: https://xxx.com/inst/redirect?merchantNo=xxxx&sign=xxxxxx&jsonEnc=xxxxx&keyEnc=xxxxxx
5 请求域名
测试环境:https://test.acquire.payroad.cn
生产环境: