余额转账

接入 Ping++ 发起余额转账,仅需要 Ping++ Server SDK 即可。服务器端需要做的就是向 Ping++ 请求 balance_transfer 接口,并且判断余额转账对象的状态,具体步骤如下:

  1. 设置 API-Key
  2. SDK 验证签名设置
  3. 从服务端发起余额转账请求
  4. 查询余额转账订单状态

第一步:设置 API-Key

Ping++ API 交易时需要设置 API-Key,Server SDK 提供了设置的方法。如果你直接使用 API ,需要在 header 中加入 Authorization,格式是 Authorization: Bearer API-Key。

\Pingpp\Pingpp::setApiKey('sk_test_ibbTe5jLGCi5rzfH4OqPW9KC');
Pingpp.apiKey = "sk_test_ibbTe5jLGCi5rzfH4OqPW9KC";
var pingpp = require('pingpp')('sk_test_ibbTe5jLGCi5rzfH4OqPW9KC');
pingpp.api_key = 'sk_test_ibbTe5jLGCi5rzfH4OqPW9KC'
Pingpp.api_key = "sk_test_ibbTe5jLGCi5rzfH4OqPW9KC"
pingpp.Key = "sk_test_ibbTe5jLGCi5rzfH4OqPW9KC"
Pingpp.Pingpp.SetApiKey("sk_test_ibbTe5jLGCi5rzfH4OqPW9KC");

第二步:SDK 验证签名设置

为了进一步增强交易请求的安全性,Ping++ 交易接口针对所有的 POST 和 PUT 请求已经新增 RSA 加密验签功能。如果使用该签名验证功能,你需要生成密钥,然后将私钥配置到你的代码中,公钥上传至 Ping++ 管理平台并启用验签开关。首先你需要本地生成 RSA 公钥和私钥,生成方法请参考:如何获取 RSA 公钥和私钥?

设置请求签名密钥

你需要在代码中设置请求签名的私钥(rsa_private_key.pem),可以读取配置私钥文件的路径或者直接定义变量。你如果通过 API 接口校验的话,需要生成 RSA 签名(SHA256)并在请求头中添加 Pingplusplus-Signature,如果使用 SDK 的话只需要配置私钥即可。

\Pingpp\Pingpp::setPrivateKeyPath(__DIR__ . '/your_rsa_private_key.pem');
Pingpp.privateKeyPath = "/path/to/your_rsa_private_key.pem";
pingpp.setPrivateKeyPath(__dirname + "/your_rsa_private_key.pem");
pingpp.private_key_path = 'your_rsa_private_key.pem'
Pingpp.private_key_path = File.dirname(__FILE__) + '/your_rsa_private_key.pem'
privateKey, err := ioutil.ReadFile("your_rsa_private_key.pem")
Pingpp.Pingpp.SetPrivateKeyPath(@"../../your_rsa_private_key.pem");

上传公钥至 Ping++ 管理平台

设置完代码中的私钥,你需要将已经生成的公钥(rsa_public_key.pem)填写到 Ping++ 管理平台上。 配置路径: 登录 Ping++ 管理平台->点击右上角公司名称->企业面板->开发参数->商户 RSA 公钥->将你的公钥复制粘贴进去并且保存->先启用 Test 模式进行测试->测试通过后启用 Live 模式

rsa_keys_setting

注意: 一旦上传公钥至 Ping++ 管理平台并启用 Live 模式,则验证签名功能即时生效,Ping++ 会立即验证你的真实线上交易验签请求。如果私钥为空或错误,则会交易失败,所以请确保测试模式正常后再启用 Live 开关。

第三步:从服务端发起余额转账请求

调用 Ping++ Server SDK 发起余额转账请求,发起请求所需参数具体可参考 API 文档

$balance_transfer = \Pingpp\BalanceTransfer::create(
[
'amount' => 10, // 用户收到转账的余额,单位:分
'user_fee' => 0, // 向发起转账的用户额外收取的手续费,单位:分
'user' => 'user_001', // 发起转账的用户 ID(可以是 C类用户 或 B类用户,但不能填 0)
'recipient' => '0', // 接收转账的用户 ID(可以是 C类用户 或 B类用户,可以为 0)
'order_no' => substr(md5(time()), 0, 10), // 商户订单号,必须在商户系统内唯一
'description' => 'Your description', // 描述
'metadata' => [], // metadata 元数据
]
);
Map<String, Object> params = new HashMap<String, Object>();
params.put("user", "test_user_001");
params.put("recipient", "test_user_003");
params.put("amount", 10);
params.put("order_no", "2017" + System.currentTimeMillis());
params.put("description", "Balance transfer description.");
// 创建 balance_transfer 方法
// 参数: params
BalanceTransfer obj = BalanceTransfer.create(params);
var order_no = new Date().getTime().toString().substr(0, 10);
var params_create = {
'user': 'test_user_001', // 发起转账的用户 ID(可以是 customer 或 business,但不能填 0)必传
'recipient': 'test_user_003', // 接收转账的用户 ID(可以是 customer 或 business,可以为 0)必传
'order_no': order_no, // 商户订单号,必须在商户系统内唯一 必传
'user_fee': 0, // 向发起转账的用户额外收取的手续费,单位:分 可选
'amount': 1, // 用户收到转账的余额,单位:分 必传
'description': 'Balance transfer description.' // 描述 可选
};
pingpp.balanceTransfers.create(APP_ID, params_create, function(err, balanceTransfer) {
if (err != null){
console.log('pingpp.balanceTransfers.list fail:', err);
}
// YOUR CODE
});
params = {
"amount": 100, # 支付受赠余额,单位:分
"user": "user_test_01", # 发起转账的用户 ID(可以是 customer 或 business,但不能填 0)
"recipient": "user_test_02", # 接收转账的用户 ID(可以是 customer 或 business,可以为 0)
"order_no": str(int(random.uniform(100000000, 200000000))), # 商户订单号,必须在商户系统内唯一
"description": "Your description", # 描述
"metadata": {} # metadata 元数据
}
print 'create balance_bonus', pingpp.BalanceTransfer.create(**params)
params = {
:order_no => order_no, # 转账订单号
:amount => 1, # 转账总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100)
:user => existed_user_id_for_balance_transfer, # 转出用户
:recipient => existed_user_id, # 转入用户
:description => "用户间转账" # 描述
}
o = Pingpp::BalanceTransfer.create(
params,
{ :app => get_app_id }
)
func (c *BalanceTransferDemo) New() (*pingpp.BalanceTransfer, error) {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
orderno := r.Intn(999999999999999)
params := &pingpp.BalanceTransferParams{
Amount: 1,
User: "demoUser",
Recipient: "demoUser2",
Order_no: fmt.Sprintf("%d", orderno),
Description: "转账",
}
return balanceTransfer.New(c.demoAppID, params)
}
var createParams = new Dictionary<string, object>
{
{"amount",10}, //用户收到转账的余额,单位:分
{"user_fee", 0}, //向发起转账的用户额外收取的手续费,单位:分
{"user", "user_test_01"}, //发起转账的用户 ID(可以是 customer 或 business,但不能填 0)
{"recipient", "user_test_02"}, //接收转账的用户 ID(可以是 customer 或 business,可以为 0)
{"order_no", new Random().Next(1, 999999999).ToString()}, //商户订单号,必须在商户系统内唯一
{"description", "Your Description"}, // 描述
{"metadata", new Dictionary<string,object>{}} //metadata 元数据
};
var balanceTransfer = BalanceTransfer.Create(appId, createParams);;

Ping++ 收到余额转账请求后返回给你的服务器一个 Balance Transfers 对象,示例:

{
"id": "311117071315154300000100",
"object": "balance_transfer",
"app": "app_1Gqj58ynP0mHeX1q",
"created": 1496728534,
"livemode": false,
"status": "succeeded",
"amount": 1000,
"order_no": "2017071110259981",
"user": "user_007",
"recipient": "user_008",
"user_fee": 0,
"user_balance_transaction": "310317060612081500000101",
"recipient_balance_transaction": "310317060612081500000201",
"description": "余额转账",
"metadata": {}
}

第四步:查询余额转账订单状态

创建余额转账订单时,会实时返回的余额转账 Balance Transfers 的订单状态。如需查询,可以主动调用余额转账查询接口来获得交易的状态。

查询 Balance Transfer 对象

$balance_transfer = \Pingpp\BalanceTransfer::retrieve('661170807435256330240000');
BalanceTransfer obj = BalanceTransfer.retrieve("660170821690361139200002");
pingpp.balanceTransfers.retrieve(APP_ID,
'660170829413280122880001', // BalanceTransfers ID
function(err, balanceTransfer) {
if (err != null){
console.log('pingpp.balanceTransfers.retrieve fail:', err);
}
// YOUR CODE
});
pingpp.BalanceTransfer.retrieve("660170815382093332480000")
o = Pingpp::BalanceTransfer.retrieve(
existed_balance_transfer_id,
{ :app => get_app_id }
)
func (c *BalanceTransferDemo) Get() (*pingpp.BalanceTransfer, error) {
return balanceTransfer.Get(c.demoAppID, c.demoTransferId)
}
BalanceTransfer.Retrieve(appId, balanceTransfer.Id);

查询 Balance Transfer 对象列表

$params = [
'page' => 1,
'per_page' => 10,
];
$balance_transfer = \Pingpp\BalanceTransfer::all($params);
Map<String, Object> params = new HashMap<>();
params.put("page", 1);
params.put("per_page", 10);
// 查询 balance_transfer 列表方法
// 参数: params
BalanceTransferCollection objs = BalanceTransfer.list(params);
var params_list = {
'page': 1,
'per_page': 3
};
pingpp.balanceTransfers.list(APP_ID, params_list, function(err, data) {
if (err != null){
console.log('pingpp.balanceTransfers.list fail:', err);
}
// YOUR CODE
});
pingpp.BalanceTransfer.list()
o = Pingpp::BalanceTransfer.list(
{ :per_page => 3 },
{ :app => get_app_id }
)
func (c *BalanceTransferDemo) List() (*pingpp.BalanceTransferList, error) {
params := &pingpp.PagingParams{}
params.Filters.AddFilter("page", "", "1") //页码,取值范围:1~1000000000;默认值为"1"
params.Filters.AddFilter("per_page", "", "2") //每页数量,取值范围:1~100;默认值为"20"
return balanceTransfer.List(c.demoAppID, params)
}
BalanceTransfer.List(appId, new Dictionary<string, object>
{
{"page", 1},
{"per_page", 10}
}
);

注意事项

  1. 创建 Balance Transfer 余额转账对象,即发起一次余额转账请求。返回的 Balance Transfer 对象中包含转账的结果,可通过 status 字段判断是否转账成功。若 status 为 succeeded 则成功。

  2. 该接口支持的是用户之间的余额转账,不支持你(企业用户)向用户转账,如果要发起 B2C 转账,请使用 企业付款

  3. 使用此接口必须保证用户可提现余额大于0。

下一步余额明细