Payment Kit provides a series of APIs related to the payment system. To reduce the workload of API integration, Maven dependencies of the Java version are provided for cloud service interconnection.
You can use Maven to set up the server development environment and quickly use the APIs provided by Huawei Pay.
You can download the sample code for the server to quickly complete the integration of the merchant server.
Due to service development requirements, the API response and callback notification request parameters may change. If you implement the signature verification logic by yourself, you must convert the original character string into a Map object for signature verification and then convert the Map object into a custom service object, ensuring that the signature verification is successful.
Before using the provided sample code to integrate Huawei Pay, ensure that the network connection is normal and the Maven dependency can be properly obtained from the Huawei Pay repository address.
Development environment: JDK 1.8 or later
The repository address has been configured in the sample code file pom.xml. If the dependency cannot be obtained properly, add the Maven repository address of Huawei Pay to the Maven configuration file settings.xml.
<mirror> <id>central</id> <mirrorOf>central</mirrorOf> <url>https://developer.huawei.com/repo/</url> </mirror>
The Maven coordinates of the JAR package have been added to the sample code file pom.xml. If a merchant builds a project by themself, add the following coordinates to the pom.xml file:
<dependency> <groupId>com.huawei.petalpay</groupId> <artifactId>pay-java</artifactId> <version>1.0.0.331</version> </dependency>
Add the following merchant-related configurations to the sample code configuration file src/main/resources/petalpayconfig.properties:
Merchant ID, which can be obtained by querying the merchant ID information.
Merchant private key, which can be obtained by referring to Preparing the Certificates.
Signature type of the merchant private key, which can be RSA or SM2.
Merchant certificate ID, which can be obtained by referring to Uploading the Merchant Certificate.
Signature verification public key of Payment Kit, which can be obtained by referring to Downloading the Huawei Pay Certificate.
(Optional) Encryption public key of Payment Kit, which needs to be configured when sensitive input fields (marked in the API) of the API need to be encrypted. For details, please refer to Sensitive Information Processing.
App ID associated with the merchant ID.
Here is a configuration example:
# Merchant ID PETALPAY.MERC_NO=121540000*** # Merchant private key PETALPAY.MERC_PRIVATE_KEY=MIIJQwIBADAN=9w0BAQEFAASCCS0wg******************************CldcDlDCSsdfDceCSDr+RyvJdfcXssdEA= # Merchant certificate ID PETALPAY.MERC_AUTH_ID=101540200089*** # Signature type of the merchant private key PETALPAY.SIGN_TYPE=RSA # Domain name of Payment Kit PETALPAY.SERVER_HOST=https://petalpay-developer.cloud.huawei.com.cn # Signature verification public key of Payment Kit PETALPAY.HW_PAY_PUBLIC_KEY_FOR_CALLBACK=6D015316F09CB747E4467******************************DB46DA4BD0960ADD500D84912 # (Optional) Encryption public key of Payment Kit PETALPAY.HW_PUBLIC_KEY_FOR_SESSIONKEY=042A7D32FA19C29D3E722D6C4ACAC0B******************************E5A5B1C8120DAC9882E4B093B9CE7A38296F87F41747D319A # App ID associated with the merchant ID PETALPAY.APPID=111831***
Obtain the object for initiating a request client.
You can use the getMercConfig method provided by the MercConfigUtil class to quickly obtain the PetalPayConfig object to build a request client. For details about how to obtain and configure the corresponding configuration items, please refer to Initializing Configurations.
// Merchant configuration
public static PetalPayConfig getMercConfig() {
return PetalPayConfig.builder().callerId(MERC_NO) // (Mandatory) Merchant ID
.appId(APP_ID) // (Mandatory) App ID associated with the merchant ID
.privateKey(MERC_PRIVATE_KEY) // (Mandatory) Merchant private key
.authId(MERC_AUTH_ID) // (Mandatory) Merchant certificate ID
.signType(SIGN_TYPE) // (Optional) Merchant public/private key type. The default value is RSA.
.petalpayPublicKey(HW_PAY_PUBLIC_KEY_FOR_CALLBACK) // (Optional) Signature verification public key. (This parameter corresponds to the API-level configuration **needVerifyRsp**. The public key is the same as the signature verification public key for the merchant notification callback.)
.domainHost(SERVER_HOST).build();
} Method 1: Use the default request client utility class. The following is an example of using PetalPayConfig to construct a request client object:
private static PetalPayClient payClient = new DefaultPetalPayClient(MercConfigUtil.getMercConfig());
Method 2: Customize the request client utility class. If you need to customize the API request client to handle operations such as logging, you can inherit PetalPayClient for implementation. The following is an example:
public class MercPetalPayClient extends PetalPayClient {
public MercPetalPayClient(PetalPayConfig petalPayConfig) {
super(petalPayConfig);
}
@Override
public String doPost(String url, Map<String, String> headers, String requestBody) throws Exception {
// Implement the POST request on your service side.
}
@Override
public String doGet(String url, Map<String, String> headers, String requestBody) throws Exception {
// Implement the GET request on your service side.
}
}
The latest open APIs are required. If the sample code is not updated in a timely manner and the default object information provided for API requests is not found, you can directly call the execute method of PetalPayClient to construct API requests.
The PetalPayClient.execute() method and DefaultPetalPayClient implementation need to obtain secure random numbers through SecureRandom.getInstanceStrong(). If the server entropy is insufficient, requests may be blocked. The following handling methods are for reference:
Method 1: Use a third-party service to supplement the server entropy. The following describes how to supplement the entropy using the haveged service:
# View the entropy. cat /proc/sys/kernel/random/entropy_avail # Install haveged. yum install haveged # Start haveged. systemctl start haveged.service # Configure the haveged service to be automatically started upon system startup. systemctl enable haveged.service
Method 2: Customize the request client utility class by referring to DefaultPetalPayClient, and proactively pass tranceId through the tranceId field (it is recommended that this field be updated for each request) of the RequestConfig object to avoid request blocking caused by automatic secure random number generation through SecureRandom.getInstanceStrong().
public <T> T execute(String httpMethod, String apiUrl, Class<T> rspType, RequestConfig requestConfig, Object requestObj) throws Exception;
Assemble request parameters.
The following is an example of assembling pre-ordering request parameters:
public static PreOrderCreateRequestV2 getPreOrderCreateRequestV2() {
return PreOrderCreateRequestV2.builder()
.mercOrderNo("pay-example-" + System.currentTimeMillis()) // The order ID changes every time. Replace pay-example- with the order prefix of the merchant.
.appId(MercConfigUtil.APP_ID) // Set the app ID to the one bound to the merchant.
.mercNo(MercConfigUtil.MERC_NO) // Merchant ID.
.tradeSummary("Product brief name") // Change this to the product brief name.
.totalAmount(2L)
.callbackUrl("https://www.xxxxxx.com/hw/pay/callback") // Callback notification URL, which must be an HTTPS URL that can be directly accessed. The value can contain a maximum of 512 characters. Replace it with the correct result notification callback URL.
.build();
} Request a service API.
The call URI varies with the API. For details, please refer to API Reference.
The following is an example of an app pre-ordering request:
public CommonResponse aggrPreOrderForAppV2() {
// Assemble the object.
PreOrderCreateRequestV2 preOrderReq = getPreOrderCreateRequestV2();
PreOrderCreateResponse response = null;
try {
response = payClient.execute("POST", "/api/v2/aggr/preorder/create/app", PreOrderCreateResponse.class,
preOrderReq);
} catch (Exception e) {
// TODO: Handle exceptions.
log.error("request error ", e);
return CommonResponse.buildErrorRsp(e.getMessage());
}
if (!validResponse(response)) {
// TODO: Handle exceptions.
log.error("response is invalid ", response);
return CommonResponse.buildFailRsp(response);
}
// Obtain prepayId to construct orderStr and return it.
return CommonResponse.buildSuccessRsp(payClient.buildOrderStr(response.getPrepayId()));
}
public static boolean validResponse(BaseGwRspWithSign rsp) {
return rsp != null && "000000".equals(rsp.getResultCode());
} You can use the VerifyTools.getCallbackResult method to automatically process the callback result signature verification and return a response to the Huawei Pay server, and implement the CallBackHandleInterface API to process the callback result.
The following is an example of notification callback processing:
public CallBackBaseResponse transactionResultNotify(@RequestBody Object callbackRequest) {
String callbackStr = JSONObject.toJSONString(callbackRequest);
return VerifyTools.getCallbackResult(callbackStr, MercConfigUtil.HW_PAY_PUBLIC_KEY_FOR_CALLBACK, new CallBackHandleInterface() {
@Override
public void fail(CallBackBaseResponse response, String reqString) {
// No byte stream is obtained or the signature verification fails.
// Perform service processing of the merchant.
log.error("CallBack failed: ", response != null ? response.getResultCode() : null);
}
@Override
public void success(String reqString) {
NotifyPaymentReq callbackReq = JSONObject.parseObject(reqString, NotifyPaymentReq.class);
// The signature verification is successful. Perform service processing of the merchant.
}
});
} For details about the notification callback requirements, please refer to Notification Callback API Description.
To ensure the confidentiality of sensitive information fields (such as the user's address, bank card number, and mobile number, which will be marked in the specific API if encryption is involved) during API request communication, Payment Kit requires that such information be encrypted before being sent. If you use a service API involving field encryption, contact Huawei engineers to obtain the SM2 encryption public key. (For cooperation consultation, click here.)
Involved keys:
| Key Type | Source | Function |
|---|---|---|
| SM2 | Provided by Huawei Pay | Encrypts the SM4 key generated by you. |
| SM4 | Generated by you | Encrypts sensitive information fields. |
Processing logic:
You generate an SM4 symmetric key for encrypting sensitive data and passing the encrypted data to Huawei Pay as an input parameter.
You use the SM2 key provided by Huawei Pay to encrypt the generated SM4 symmetric key and pass the encrypted key to Huawei Pay through the PayMercAuth.sessionKey field for decrypting sensitive information.
The essence is SM4 symmetric key encryption. The sample code is as follows:
import com.huawei.petalpay.paymentservice.apiservice.client.model.MgmtSubmercRsp;
import com.huawei.petalpay.paymentservice.core.client.DefaultPetalPayClient;
import com.huawei.petalpay.paymentservice.core.client.PetalPayClient;
import com.huawei.petalpay.paymentservice.core.config.RequestConfig;
import com.huawei.petalpay.paymentservice.core.tools.SM4Util;
import com.huawei.petalpay.paymentservice.example.common.MercConfigUtil;
public class SignRegister {
public static void main(String[] args) {
PetalPayClient payClient = new DefaultPetalPayClient(MercConfigUtil.getMercConfig());
String sessionKey = SM4Util.getSM4GCMSessionKey();
String message = "xxxxxx";
RegisterSubmercReq req = new RegisterSubmercReq(SM4Util.getSM4GCMContent(sessionKey, message));
RequestConfig config = RequestConfig.builder()
.publicKeyForSessionKey(MercConfigUtil.HW_PUBLIC_KEY_FOR_SESSIONKEY)
.sessionKey(sessionKey)
.build();
try {
MgmtSubmercRsp response = payClient.execute("POST", "/api/v1/partner/mgmt/submerc/register",
MgmtSubmercRsp.class, config, req);
} catch (Exception e) {
// TODO: Handle exceptions.
}
}
static class RegisterSubmercReq {
private String message;
public RegisterSubmercReq(String message) {
this.message = message;
}
}
}