8 Payment system¶
Pico payment is a game currency payment system based on the Pico account system, and the settlement method is based on the current game currency unit under Pico (P currency).
8.1 Preparations¶
8.1.1 Get the string used for payment¶
Accesses the payment SDK, an application needs to be created on the developer platform and the corresponding string should be gotten. The application process is as follows:
Log in to the developer platform and register a Pico member (http://developer.pico-interactive.com/)
Apply to become a developer
The developers are divided into individual developers and enterprise developers, please apply according to the actual situations. After the review is submitted, we will provide feedback within 3 working days, please view the status of the developer platform in time.
View merchant ID
Once you’ve applied to become a developer, you can view the developer ID after click on the nickname in the top right corner, i.e. the merchant ID:

Figure 8.1 Developer ID
Note: Before applying for a developer, you need to become a member of Pico.
4.Get the corresponding string
The developers can enter from “Application Management” to the “Creation Application” phase:

Figure 8.2 Application creation
After clicking creation application, the information about the application can be improved, including whether the application is free or paid, and how much P currency you need to pay when you pay:

Figure 8.3 Information about application
Note: Please pay key attention to the red position of the above figure, please fill out the application type carefully, and it can’t be modified once you fill it out! After the application is successfully created, the developer platform will assign a string to it, including APPKEY, APPID, APP SECRET:

Figure 8.4 APP ID, APP KEY, APP Secret
Fill in the strings
Go to Edit->Project Settings…, expand PicoMobile under the Plugins sub-item, check “Enable Payment Module”, then select “Is Foreign” according to the actual situations, and finally get the merchant (developer) ID, APPID, APP KEY., APP secret and fill them in the following location:

Figure 8.5 String filling
8.1.2 Set the callback proxy event¶
Before using payment, the callback proxy event should be set first, so that you can get the parameters output by the callback functions and set the subsequent execution flow. Here, please use the PicoPaymentSetCallbackDelegates node we provide:

Among them, On Pico Payment Exception Callback is a callback for various exceptions from payment, and the exact meaning of the other callback function parameters will be introduced in the next section which introduces its related main callback functions.
8.3 Developer server interaction¶
After the payment is completed, the payment system will send the relevant payment results and user information to the merchant, and the merchant needs to receive and process them and return a response.
When the background notifies the interaction, if the receiving of the merchant’s response by the payment system receives is not successful or overtime, the notification should be considered as failed, and the payment system will periodically re-initiate the notification through certain policies to maximize the success rate of the notification, but it may not guarantee that the notification will be eventually successful.
The same notification may be sent to the merchant system repeatedly and the merchant system must be able to process duplicate notifications correctly. The recommended practice is to firstly check the status of the corresponding service data when it receives and processes the notification, and determine whether the notification has been processed, it should be re-processed if it has not been processed, and the result return will be successful directly if it has been processed. Before the status check and processing of business data, data locks should be used for concurrency control to avoid data confusion caused by function reentry.
The merchant server needs to implement the following interface for receiving the request from the Pico server and get the payment result and user information of the Pico payment system:
Table 8.2 Interfaces that the merchant server needs to implement
Name |
Payment results callback interface |
Request Type |
POST |
Request URL |
Pay, parameter notify_url transmitted by PayOrder |
Request Format |
JSON |
Return Format |
JSON |
Is login required |
Yes |
Request Parameters |
For details, see “Table 8.3 Notification parameters in payment results notification” |
Return parameter |
![]() For details see “Table 8.4 Return results” |
Return parameter example |
{ “ret_code”:”SUCCESS”, “ret_msg”:”OK”} |
Update instruction |
Table 8.3 Notification parameters in payment results notification
Field Name |
Param Name |
Required |
Type |
Description |
---|---|---|---|---|
Return Status Code |
ret_code |
Yes |
String |
SUCCESS/FAIL This field is the communication identifier, rather than transaction identifier,and if the transaction is successful should be determined based on the check on result_code. |
Return Message |
ret_msg |
No |
String |
For return information, in case of not empty, it may be caused due to error Signature failure and parameter format check error. |
Error Code |
sub_code |
No |
String |
Error code |
Error code description |
sub_msg |
No |
String |
Wrongly returned information error |
Pico pay order number |
trade_no |
Yes |
String |
Pico payment order number |
Merchant order number |
out_trade_no |
Yes |
String |
The order number within the merchant system |
App ID |
app_id |
Yes |
String |
Application APP_ID approved by the platform |
Merchant ID |
mch_id |
Yes |
String |
Assigned merchant number for payment |
User ID |
open_id |
Yes |
String |
Unique identifier of the user under the merchant appid |
Device ID |
device_id |
No |
String |
Terminal device number |
Random string |
nonce_str |
Yes |
String |
Random string: no longer than 32 bits. Recommended random number generation algorithm |
Signature |
signature |
Yes |
String |
For signature, see the signature generation algorithm |
Business Result |
result_code |
Yes |
String |
SUCCESS/FAIL |
Transaction type |
trade_type |
Yes |
String |
Payment type |
Currency Type |
fee_type |
Yes |
String |
Currency type |
Total amount |
total_fee |
Yes |
String |
Total order amount |
Paid-in amount |
receipt_fee |
Yes |
String |
Paid-in amount |
The amount paid by the buyer |
buyer_pay_fee |
No |
String |
The amount paid by the buyer |
Voucher or Discount |
coupon_fee |
No |
String |
Voucher or discount |
Merchant data package |
attach |
No |
String |
Merchant data package, returned as it is |
Payment completion time |
pay_time |
Yes |
String |
Payment completion time, in the format: yyyy-MM-dd HH: mm:ss |
Table 8.4 Return results
Field Name |
Param |
Required |
Type |
Description |
---|---|---|---|---|
Status code returned |
ret_code |
Yes |
String |
SUCCESS/FAIL, SUCCESS indicates that the merchant has received and verified the notification successfully. |
Return information |
ret_msg |
No |
String |
For return information, in case of not empty, it may be caReturn message,if not null, it contains error message: signature failed, parameter format check error |
Special remarks: The signature verification must be performed for the contents of the payment result notification in the merchant system to prevent “false notification” due to data leakage and capital loss.
The signature verification rule is as follows:
Remove the signature parameter from the returned list of parameters, and simultaneously add key = “app_secret”, value=paykey, then sort it naturally according to the key value, separate the multiple parameters with &, and finally take MD5 encryption
Compare the encrypted string with the get signature
The signature function is as follows:
/**
* result: Map collection of gotten data
* paykey: i.e. the paykey on the developer platform.
*/
public static String createSign(Map<String, Object> result, String paykey)
{
if (result == null || result.size() == 0)
return null;
result.put("app_secret", paykey);
String sign = result.get("signature");
result.remove("signature");
String[] tmp = new String[result.size()];
int i = 0;
for (String key : result.keySet())
{
tmp[i++] = key;
}
Arrays.sort(tmp);
String sign = "";
for (String string : tmp)
{
if (m.get(string) == null)
continue;
sign += string + "=" + URLEncoder.encode(m.get(string).toString()
, "utf-8") + "&";
}
if (sign.endsWith("&"))
sign = sign.substring(0, sign.length() - 1);
Log.i(TAG, "createSign: " + sign);
String localSign = MD5.MD5(sign);
return localSign.equal(sign);
}