Since version 4.1.0(11), the contracted auto-debit scenario is supported.
After a user becomes a member of a merchant app or atomic service for a period of time, the user wants to enable auto-renewal for each month without having to manually renew the membership each month. The merchant can provide an auto-renewal option for the user to enable the function. The merchant initiates a contract signing request through the contract pre-signing API. After the signed contract takes effect, the merchant can directly initiate a PIN-free payment request based on the time specified in the contract to complete the payment and renewal when the membership expires. The user does not need to manually renew the membership each month.
Supported merchant models: direct merchant, platform merchant, and service provider
Huawei Pay agreement screen:

By integrating the contracted auto-debit capability of Payment Kit, you can initiate a payment request to deduct fee from a user's Huawei Pay account after obtaining the contracted authorization of the user. The user does not need to enter the payment password, and the payment method specified in the contract can be used to complete the deduction. The integration process is as follows.

The merchant client requests the merchant server to create a contract signing order.
The merchant server calls the pre-signing API for merchants or pre-signing API for service providers of the Payment Kit server based on the merchant model.
The Payment Kit server returns the pre-signing ID (preSignNo) to the merchant server.
The merchant server constructs the contractStr parameter and returns it to the merchant client.
The merchant client uses contractStr to call the requestContract API to launch the contract signing screen of Payment Kit.
The Payment Kit client displays the contract signing information on the contract signing screen.
The user completes the contract signing operation on the contract signing screen of the Payment Kit client.
The Payment Kit server processes the contract signing.
After the contract signing is successful, the Payment Kit server returns the contract signing result to the Payment Kit client.
The Payment Kit client displays the contract signing result screen.
After the user closes the contract signing result screen, the Payment Kit client returns to the merchant client.
After the contract signing is complete, the Payment Kit server calls the callback API passed when the merchant server calls the pre-signing API to return the contract signing result to the merchant server.
After receiving the contract signing result callback response, the merchant server performs SM2-based signature verification on the contract signing result.
After the contract signing is complete, the merchant server can call the API for direct merchants to apply for PIN-free payment or API for service providers to apply for PIN-free payment of the Payment Kit server to complete fee deduction.
After the merchant server calls the Payment Kit server API for applying for PIN-free payment, the Payment Kit server synchronously returns the PIN-free payment application result.
After the Payment Kit server successfully processes the PIN-free payment, it calls the callback API passed when the merchant server calls the PIN-free payment API to return the fee deduction result to the merchant server.
After receiving the fee deduction result callback response, the merchant server performs SM2-based signature verification on the fee deduction result.
APIs use either a promise or AsyncCallback to return the result. The APIs that use a promise provide the same functions as their counterparts that use an AsyncCallback. For details about the API, please refer to API Reference.
| API Name | Description |
|---|---|
| requestContract(context: common.UIAbilityContext, contractStr: string): Promise<void>; | Launches the contract signing screen of Payment Kit. |
| requestContract(context: common.UIAbilityContext, contractStr: string, callback: AsyncCallback<void>): void; | Launches the contract signing screen of Payment Kit. |
Call the pre-signing API for direct merchants or pre-signing API for service providers based on the merchant model to obtain preSignNo and construct the contract signing information parameter contractStr.
To ensure the security and reliability of payment orders, the input parameters in the request body and the PayMercAuth object in the request header need to be sorted and concatenated for signing. For details, please refer to Signing Rules.
The following is a snippet of the sample code for sending an open API request and constructing the contractStr parameter:
import com.huawei.petalpay.paymentservice.apiservice.client.model.BaseGwRspWithSign;
import com.huawei.petalpay.paymentservice.apiservice.client.model.PreSignRequestV2;
import com.huawei.petalpay.paymentservice.apiservice.client.model.PreSignResponse;
import com.huawei.petalpay.paymentservice.core.client.DefaultPetalPayClient;
import com.huawei.petalpay.paymentservice.core.client.PetalPayClient;
import com.huawei.petalpay.paymentservice.example.common.CommonResponse;
import com.huawei.petalpay.paymentservice.example.common.MercConfigUtil;
public class MercApiController {
private static PetalPayClient payClient = new DefaultPetalPayClient(MercConfigUtil.getMercConfig());
/**
* Call the pre-signing API.
*/
public CommonResponse contractPreSignAppV2() {
// Assemble the object.
PreSignRequestV2 preSignReq = getPreSignRequestV2();
PreSignResponse response = null;
try {
response = payClient.execute("POST", "/api/v2/contract/presign/app", PreSignResponse.class, preSignReq);
} catch (Exception e) {
// Handle exceptions.
log.error("request error ", e);
return CommonResponse.buildErrorRsp(e.getMessage());
}
if (!validResponse(response)) {
// Handle exceptions.
log.error("response is invalid ", response);
return CommonResponse.buildFailRsp(response);
}
return CommonResponse.buildSuccessRsp(payClient.buildContractStr(response.getPreSignNo()));
}
public static boolean validResponse(BaseGwRspWithSign rsp) {
return rsp != null && "000000".equals(rsp.getResultCode());
}
/**
* Assemble the pre-signing API request parameters. The merchant needs to implement the function as needed.
*/
private PreSignRequestV2 getPreSignRequestV2() {
return PreSignRequestV2.builder().appId(MercConfigUtil.APP_ID) // Set the app ID to the one bound to the merchant.
.mercContractCode("pay-example-" + System.currentTimeMillis()) // Contract code, which changes for each request. Replace pay-example- with the order prefix of the merchant.
.mercNo(MercConfigUtil.MERC_NO) // Merchant ID.
.planId("100") // Contract template ID, which is generated by Huawei Pay when the merchant submits a permission application for entrusted payment to Huawei Pay. Enter a correct contract template ID.
.callbackUrl("https://www.xxxxxx.com/hw/sign/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();
}
} The merchant client uses contractStr as a parameter to call the requestContract API to launch the contract signing screen of Payment Kit.
If the API returns a result using the .then() method, the order payment is successful. If the API returns a result using the .catch() method, the order payment fails. If the request is abnormal, you can obtain the error code through error.code. For details about the error code, please refer to Error Codes. The sample code is as follows:
import { BusinessError } from '@kit.BasicServicesKit';
import { paymentService } from '@kit.PaymentKit';
import { common } from '@kit.AbilityKit';
@Entry
@Component
struct Index {
context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
requestContractPromise() {
// Please use the actual input parameter information (**contractStr**).
const contractStr = '{"appId":"***","preSignNo":"***"}';
paymentService.requestContract(this.context, contractStr)
.then(() => {
// The contract signing is successful.
console.info('succeeded in signing');
})
.catch((error: BusinessError) => {
// The contract signing fails.
console.error(`failed to sign, error.code: ${error.code}, error.message: ${error.message}`);
});
}
build() {
Column() {
Button('requestContractPromise')
.type(ButtonType.Capsule)
.width('50%')
.margin(20)
.onClick(() => {
this.requestContractPromise();
})
}
.width('100%')
.height('100%')
}
}
If a user has not signed in, the system will automatically launch the HUAWEI ID sign-in screen, asking the user to sign in first. If the user cancels the sign-in or the sign-in fails, the contract signing process will be interrupted.
The contract signing is successful. It is not recommended to use the result returned by the client as the user's contract signing result. Instead, use the result notification received by the server or the result returned by the query API.
After the payment is successful, the Huawei Pay server calls the callback API provided by you to send the contract signing information to your server. For details about the callback information, please refer to the contract signing result callback notification.
The callback API is the callback URL specified by the input parameter callbackUrl when you call the pre-signing API or the callback URL configured in the signing template.
To ensure the validity of the information, the merchant server needs to perform SM2-based signature verification on the returned contract signing information. Pay attention to the following during signature verification:
Use the complete content of the notification for signature verification.
Before signature verification, sort and combine the returned data. The sign field indicates the signature value. The content to be verified must exclude the sign field.
Use the Huawei Pay certificate as the public key for signature verification.
After implementing the preceding capabilities, you can also call the following APIs to perform order-related operations.