第三方支付方案
2019-10-31
1,797 views
10 min read
方案图
一般支付API文档
参考此文档开发API
商户私钥生成方法
openssl genrsa -out app_private_key.pem 2048 #生成私钥
openssl pkcs8 -topk8 -inform PEM -in app_private_key.pem -outform PEM -nocrypt -out app_private_key_pkcs8.pem #Java需要将私钥转换成PKCS8格式
openssl rsa -in app_private_key.pem -pubout -out app_public_key.pem #生成公钥
经过以上步骤,开发者可以在当前文件夹中(OpenSSL运行文件夹),看到app_private_key.pem(RSA私钥,非Java适用)、app_private_key_pkcs8.pem(pkcs8格式RSA私钥,Java适用)和app_public_key.pem(开发者RSA公钥)3个文件。开发者将私钥保留,将公钥上传到平台,用于验证签名。
公钥需要去除 -----BEGIN PUBLIC KEY-----
和 -----END PUBLIC KEY-----
并转成一行字符串
公共参数
参数 | 类型 | 是否必填 | 最大长度 | 描述 | 示例值 |
---|---|---|---|---|---|
appID | String | 是 | 32 | 平台分配的应用ID | 2019042300007148 |
mchID | String | 是 | 32 | 平台分配的商户ID | 2019042600005436 |
signType | String | 是 | 10 | 生成签名字符串所使用的签名算法类型,目前支持SHA256WithRSA | SHA256WithRSA |
sign | String | 是 | 344 | 商户请求参数的签名串,详见签名 | 详见示例 |
deviceInfo | String | 否 | 256 | 终端设备信息 | {"phone": "130xxxxxxxx"} |
nonceStr | String | 是 | 64 | 随机字符串 | 7JcFHZLaYHjzDZRCdXCZWoXg |
公共返回结果
参数 | 类型 | 是否必填 | 最大长度 | 描述 | 示例值 |
---|---|---|---|---|---|
appID | String | 是 | 32 | 调用接口时提供的应用ID | 2019042300007148 |
mchID | String | 是 | 32 | 调用接口时提供的商户ID | 2019042600005436 |
nonceStr | String | 是 | 64 | 服务器返回的随机字符串 | 7JcFHZLaYHjzDZRCdXCZWoXg |
signType | String | 是 | 10 | 服务器使用的签名算法类型,目前支持SHA256WithRSA | SHA256WithRSA |
sign | String | 是 | 344 | 服务器提供的签名,详见验签 | 详见示例 |
签名
1.将消息体序列化为JSON(不包含sign字段且要求为未经过pretty的最小JSON)
2.对消息体执行SHA256WithRSA签名过程(标准算法)
2.1 对消息体进行SHA256取得摘要
2.2 用开发者私钥对摘要进行RSA加密
2.3 上步的结果即为平台所需要的签名
验签
1.将消息体序列化为JSON(不包含sign字段且要求为未经过pretty的最小JSON)
2.对消息体执行SHA256WithRSA验签过程(标准算法)
2.1 对消息体进行SHA256取得摘要
2.2 用平台公钥对摘要进行RSA解密
2.3 上步结果与sign对比,一致即为验签通过
错误码
Code | 描述 | 原因 | 解决方案 |
---|---|---|---|
100001 | 参数错误 | 参数格式有误或者未按规则上传 | 请确认参数问题 |
100002 | appID不存在 | 系统中缺少APPID | 请检查appID,或联系管理员分配 |
100003 | mchID不存在 | 系统中缺少mchID | 请检查mchID,或联系管理员分配 |
100004 | appID与mchID不匹配 | 提供的appID与mchID不匹配 | 请检查mchID与appID是否匹配 |
100005 | 签名错误 | 参数签名结果不正确 | 请检查签名参数和方法是否都符合签名算法要求 |
100006 | 散户订单号重复 | 同一笔交易不能多次提交 | 请核实商户订单号是否重复提交 |
统一下单接口
请求地址
环境 | HTTPS请求地址 | HTTP方法 | 请求 Content-Type | 返回 Content-Type |
---|---|---|---|---|
正式环境 | pay/order | POST | application/json; charset=utf-8 | application/json; charset=utf-8 |
请求参数
参数 | 类型 | 是否必填 | 最大长度 | 描述 | 示例值 |
---|---|---|---|---|---|
body | String | 是 | 128 | 商品描述 | VIP1充值 |
detail | String | 否 | 4096 | 商品详情 | VIP1会员充值 |
customData | String | 否 | 1024 | 用户自定义数据 查询订单时原样返回 | {"foo":"bar"} |
externalOrderID | String | 是 | 256 | 商户订单号 | 8B4TtR228vrJ863eiuNCTB38 |
currencyCode | String | 是 | 16 | 货币类型 | BTC |
amount | Int | 是 | 64bit | 订单金额 | 666 |
timeExpire | String | 是 | 24 | 订单失效时间 最长为订单调用时刻 + 10天 | 2019-06-03T16:00:00.000Z |
limitPay | String | 否 | 32 | 限制支付方式,多个方式用, 号分割 | BTC,ETH |
notifyURL | String | 否 | 1024 | 退款结果回调地址 |
返回结果
当HTTP Code为 200
时
参数 | 类型 | 是否必填 | 最大长度 | 描述 | 示例值 |
---|---|---|---|---|---|
payID | String | 是 | 128 | 支付订单号 | B8r97wQ22cNk2GUX46c4ju4D |
当HTTP Code为 500
时
参数 | 类型 | 是否必填 | 最大长度 | 描述 | 示例值 |
---|---|---|---|---|---|
code | Int | 是 | 64bit | 错误码 | 详见错误码 |
detail | String | 否 | 4096 | 详情 | 详见错误码 |
收银台页面
请求地址
| 环境 | HTTPS请求地址 | HTTP方法 |
| - | ---- | - | - | - |
| 正式环境 | pay/order/ | GET | application/json; charset=utf-8 | application/json; charset=utf-8 |
查询订单
请求地址
环境 | HTTPS请求地址 | HTTP方法 | 请求 Content-Type | 返回 Content-Type |
---|---|---|---|---|
正式环境 | pay/order/ | GET | application/json; charset=utf-8 | application/json; charset=utf-8 |
请求参数
参数 | 类型 | 是否必填 | 最大长度 | 描述 | 示例值 |
---|---|---|---|---|---|
externalOrderID | String | 是 | 256 | 商户订单号 | 8B4TtR228vrJ863eiuNCTB38 |
返回结果
当HTTP Code为 200
时
参数 | 类型 | 是否必填 | 最大长度 | 描述 | 示例值 |
---|---|---|---|---|---|
currencyCode | String | 是 | 16 | 货币类型 | BTC |
amount | Int | 是 | 64bit | 订单金额 | 666 |
paymentTime | String | 是 | 24 | 订单支付时间 | 2019-06-03T16:00:00.000Z |
payID | String | 是 | 128 | 支付订单号 | 8B4TtR228vrJ863eiuNCTB38 |
tradeStatus | String | 是 | 4096 | 交易状态 | SUCCESS |
SUCCESS — 支付成功 | |||||
REFUND — 退款 | |||||
NOTPAY — 未支付 | |||||
CLOSED — 已关闭 | |||||
USERPAYING -- 用户支付中 | |||||
PAYERROR -- 支付失败(未知原因原因) |
当HTTP Code为 500
时
参数 | 类型 | 是否必填 | 最大长度 | 描述 | 示例值 |
---|---|---|---|---|---|
code | Int | 是 | 64bit | 错误码 | 详见错误码 |
detail | String | 否 | 4096 | 详情 | 详见错误码 |
关闭订单
暂未实现
请求地址
环境 | HTTPS请求地址 | HTTP方法 | 请求 Content-Type | 返回 Content-Type |
---|---|---|---|---|
正式环境 | pay/order//close | POST | application/json; charset=utf-8 | application/json; charset=utf-8 |
申请退款
请求地址
环境 | HTTPS请求地址 | HTTP方法 | 请求 Content-Type | 返回 Content-Type |
---|---|---|---|---|
正式环境 | pay/order//refund | POST | application/json; charset=utf-8 | application/json; charset=utf-8 |
请求参数
参数 | 类型 | 是否必填 | 最大长度 | 描述 | 示例值 |
---|---|---|---|---|---|
externalOrderID | String | 是 | 256 | 商户订单号 | 8B4TtR228vrJ863eiuNCTB38 |
currencyCode | String | 是 | 16 | 货币类型 | BTC |
refundAmount | Int | 是 | 64bit | 退款金额 | 666 |
refundDesc | String | 否 | 256 | 退款原因,若商户传入,会在下发给用户的退款消息中体现退款原因 | |
notifyURL | String | 否 | 1024 | 退款结果回调地址 |
返回结果
当HTTP Code为 200
时
无
当HTTP Code为 500
时
参数 | 类型 | 是否必填 | 最大长度 | 描述 | 示例值 |
---|---|---|---|---|---|
code | Int | 是 | 64bit | 错误码 | 详见错误码 |
detail | String | 否 | 4096 | 详情 | 详见错误码 |
查询退款
请求地址
环境 | HTTPS请求地址 | HTTP方法 | 请求 Content-Type | 返回 Content-Type |
---|---|---|---|---|
正式环境 | pay/order//refund | GET | application/json; charset=utf-8 | application/json; charset=utf-8 |
请求参数
参数 | 类型 | 是否必填 | 最大长度 | 描述 | 示例值 |
---|---|---|---|---|---|
externalOrderID | String | 是 | 256 | 商户订单号 | 8B4TtR228vrJ863eiuNCTB38 |
返回结果
当HTTP Code为 200
时
参数 | 类型 | 是否必填 | 最大长度 | 描述 | 示例值 |
---|---|---|---|---|---|
currencyCode | String | 是 | 16 | 货币类型 | BTC |
refundAmount | Int | 是 | 64bit | 退款金额 | 666 |
refundDesc | String | 否 | 退款原因,若商户传入,会在下发给用户的退款消息中体现退款原因 | ||
refundStatus | String | 是 | 32 | 退款状态 | SUCCESS |
SUCCESS—退款成功 | |||||
EFUNDCLOSE—退款关闭 | |||||
PROCESSING—退款处理中 | |||||
refundChannel | String | 是 | 32 | 退款渠道 | ORIGINAL |
ORIGINAL—原路退款 | |||||
OTHER—其他渠道 |
当HTTP Code为 500
时
参数 | 类型 | 是否必填 | 最大长度 | 描述 | 示例值 |
---|---|---|---|---|---|
code | Int | 是 | 64bit | 错误码 | 详见错误码 |
detail | String | 是 | 4096 | 详情 | 详见错误码 |
支付结果通知
将查询订单接口结果直接POST到notifyURL参数指定的地址
Body Content-Type 为 application/json; charset=utf-8
接口成功处理需返回200
处理异常返回500
平台会尝试再次推送(总共3次)
注意验证服务器签名
退款结果通知
将查询退款接口结果直接POST到notifyURL参数指定的地址
Body Content-Type 为 application/json; charset=utf-8
接口成功处理需返回200
处理异常返回500
平台会尝试再次推送(总共3次)
注意验证服务器签名
Previous Post
Spring boot 部署脚本
Next Post
全新自制主题纪念
Or you can contact me by Email