Accept payments
This chapter goes through the process of integrating the capability of accepting payments by using Alipay+ client SDK and Alipay+ APIs.
To make a payment, the MPP needs to take the following steps:
- Step 1: Establish a session between Alipay+ client SDK and Alipay+
- Step 2: Obtain logos of acceptance marks and payment code
- Step 3: Process the payment
The process is used in the scenario where a user uses an MPP app to present a payment code to the merchant.
Workflow
To accept a payment, the MPP must obtain the payment code before proceeding with the payment process.
The following figure illustrates the payment flow:
Figure 1: Payment workflow
The payment flow consists of the following steps:
- The user opens the Payment Code page in the MPP app (Step 1).
- The MPP app calls the getAcceptanceMarkLogos API from Alipay+ client SDK to obtain the logos of acceptance marks (Step 2).
- The MPP app obtains the logos of acceptance marks and displays them on the Payment Code page (Steps 3-4).
- When the user opens the payment code page, the MPP app also initiates a request for a payment code (Step 5).
- The MPP app calls the getPaymentCode API to request the payment code from Alipay+ client SDK (Step 6).
- Alipay+ client SDK creates a session with Alipay+ . If a session already exists, this step is skipped (Step 7).
- Alipay+ client SDK obtains the payment code from Alipay+ and returns it to the MPP app (Steps 8-10).
- The MPP app displays the payment code (Step 11).
- The merchant scans the payment code and then sends a request to initiate a payment (Steps 12-14).
- Alipay+ decodes the payment code to obtain customerId and calls the pay API to send the order information with customerId to the MPP server (Steps 15-16).
- The MPP server processes the payment and returns the payment result to Alipay+ (Steps 17-18).
- Alipay+ returns the payment result to the merchant (Steps 19-20).
- The MPP server sends the payment result notification to the MPP app, which then displays the payment result page to the user (Steps 21-22).
Before you begin
Before you start the integration with Alipay+ User-presented Mode Payment product, ensure that you integrate Alipay+ client SDK. See Alipay+ client SDK integration guide for details.
Step 1: Establish a session between Alipay+ client SDK and Alipay+
Note: Skip this step if the session is already created.
To ensure secure communication between Alipay+ and Alipay+ client SDK, a session is created.
The following figure illustrates the workflow of establishing a session:
Figure 2. Workflow of establishing a session
Complete the following steps to establish a session:
- Alipay+ client SDK calls the getAuthCode API to obtain the authorization code from MPP app (Step 1).
- The MPP app obtains the authorization code from its server and then returns it to Alipay+ client SDK (Steps 2-4).
- Alipay+ client SDK sends the authorization code to Alipay+(Step 5).
- Alipay+ calls the applyToken API to obtain the access token from the MPP server and the MPP server returns the access token and customer ID to Alipay+ (Steps 6-8).
- Alipay+ creates the session ID (Step 9).
- Alipay+ returns the session ID to Alipay+ client SDK and the session is created (Step 10).
Read the following sections for the main steps:
Step 1.1: Call the getAuthCode API to obtain the authorization code
Alipay+ client SDK calls the getAuthCode API to obtain the authorization code from MPP. The value of scopes is BASE_USER_INFO
. MPP returns the authorization code by authCallback. For the samples for Android and iOS, see Alipay+ client SDK integration guide.
Step 1.2: Obtain the access token and customer ID from the MPP
Alipay+ client SDK sends the authorization code to Alipay+. With the authorization code received, Alipay+ calls the applyToken API to request an access token. In this case, the value of acquirerId
is fixed as 2052666000000000
, which represents Alipay+.
Alipay+ can request an access token with the authCode received.
Process flow
The API request contains the following fields:
No. | Field | Remarks |
1 | pspId | / |
2 | acquirerId | / |
3 | grantType | Specify the value as |
4 | authCode | The authCode generated by MPP must be within 32 bits. The first 8 digits of the authorization code must be in the format of |
5 | refreshToken Optional | Required when grantType is |
6 | passThroughInfo Optional | / |
The API response contains the following fields:
No. | Field | Remarks |
3 | result | If result.resultStatus is |
4 | accessToken Optional | Required when the authorization token application request is successful, the AuthClient can use accessToken to access the corresponding user's resource scope. This token must be within 128 bits. |
5 | accessTokenExpiryTime Optional | Must be returned when the authorization token application request is successful. |
6 | refreshToken Optional | Must be returned when the authorization token application request is successful. This token must be within 128 bits. |
7 | refreshTokenExpiryTime Optional | Must be returned when the authorization token application request is successful. |
8 | customerId Optional | Must be returned when the authorization token application request is successful. |
9 | passThroughInfo Optional | / |
Processing logic
If the value of scopes is BASE_USER_INFO
, it is recommended that you set the validity period of the access token to 10 minutes when generating the access token.
Sample
Request sample
{
"acquirerId":"10221880000000****",
"pspId":"10220880000000****",
"authCode": "281010133AB2F588D14B43231234****",
"grantType": "AUTHORIZATION_CODE",
}
Response sample
{
"result": {
"resultCode": "SUCCESS",
"resultMessage": "Success",
"resultStatus": "S"
},
"accessToken": "281010033AB2F588D14B43238637264FCA5A****",
"accessTokenExpiryTime": "2019-06-06T12:12:12+08:00",
"refreshToken": "2810100334F62CBC577F468AAC87CFC6C910****",
"refreshTokenExpiryTime": "2019-06-08T12:12:12+08:00",
"customerId":"278980891233213455671****"
}
For more information about how to use the API (such as the parameter description), see applyToken for details.
Step 1.3: Alipay+ creates the session and returns the session ID to Alipay+ client SDK
Alipay+ creates the session, and associates sessionId
with the returned customerId
and accessToken
. Alipay+ returns the session ID to Alipay+ client SDK. The session is created between Alipay+ and Alipay+ client SDK.
By default, the validity period of the session is 30 minutes (set by Alipay+ for security reasons). Auth login is normally valid for 360 hours unless the user logout.
Step 2: Obtain logos of acceptance marks and payment code
To render the payment code page, the MPP needs to obtain both the logos of the acceptance marks and the payment code.
Obtain logos of acceptance marks
To obtain the logos of the acceptance marks, the MPP client needs to call the acceptanceMarkLogos API from Alipay+ client SDK. The following figure illustrates the workflow of obtaining logos of acceptance marks.
Figure 3. The workflow of obtaining logos of acceptance marks
The process of obtaining the logos of acceptance marks consists of the following steps:
- The user opens the Payment Code page in the MPP app (Step 1).
- The MPP app calls the getAcceptanceMarkLogos API from Alipay+ client SDK to obtain the logos of acceptance marks. The MPP can determine whether to pass in the region parameter in the API request (Step 2).
- (Optional) If the configuration information is not cached locally or if more than 60 minutes are elapsed since Alipay+ client SDK last pulls the configuration information, Alipay+ client SDK calls the fetchConfig API to obtain the configuration information from the Alipay+ server (Steps 3-4).
Note:
The time interval between two pulls is configurable and the default time interval is 60 minutes.
- The MPP app obtains the logos of acceptance marks in either of the following ways: (Steps 5-9)
- If the region parameter is not passed in by the MPP, Alipay+ client SDK determines the user's current location based on the cellular service provider information and/or the time zone obtained from the MPP app. Alipay+ client SDK then retrieves the logos of acceptance marks from the configuration information and returns them to the MPP app.
- If the region parameter is passed in by the MPP, Alipay+ client SDK directly obtains the logos of acceptance marks from the configuration information and returns them to the MPP app.
Note:
- If Alipay+ is not supported in the user's current location, Alipay+ client SDK returns an empty array.
- Since the Alipay+ logo is mandatory to be displayed on the Payment Code page, the MPP needs to configure the Alipay+ logo in advance and Alipay+ client SDK does NOT return the Alipay+ logo.
- The MPP app displays the logos of acceptance marks accordingly on the Payment Code page (Step 10).
Obtain the payment code
Complete the following steps to obtain the payment code fromAlipay+ client SDK:
- Initialize Alipay+ client SDK
- Call the getPaymenCode API to obtain the payment code
1. Initialize Alipay+ client SDK
Before Mobile Payment Provider uses the features provided by Alipay+ client SDK, call the init API that is for Android or the initWithContext API that is for iOS to initialize the Alipay+ client SDK first.
For more information about the samples for initializing the Alipay+ Android client SDK, see Step 3: Initialize SDK in your app.
For more information about the samples for initializing the Alipay+ iOS client SDK, see Step 3: Initialize SDK in your app.
2. Call the getPaymenCode API to obtain the payment code
The Mobile Payment Provider app calls the getPaymentCode API to obtain the payment code from Alipay+ client SDK.
Note: When calling the getPaymentCode API, the MPP app must pass in information about the region that is selected by the user. The region list that is displayed for selection must be configurable at the MPP server side.
Processing logic
If the getPaymentCode call succeeds, Mobile Payment Provider must display the payment code. And, if the call fails, Mobile Payment Provider must be able to automatically retry. In addition, Mobile Payment Provider should be able to manually switch the region.
Sample
Android:
String region = "CN";
IAPConnect.getPaymentCode(region, new IPaymentCodeListener() {
@Override
public void onPaymentCodeUpdated(String paymentCode) {
// handle the payment code
}
@Override
public void onPaymentCodeUpdateFailed(String errorCode, String errorMessage) {
// handle the error information
}
});
iOS:
[AlipayConnect getPaymentCode:@"CN" paymentCodeListener:self];
After the getPaymentCode API is called, Alipay+ client SDK sends the request of obtaining the payment code to Alipay+ by using sessionId
. Alipay+ returns the payment code to Alipay+ client SDK. After that, Alipay+ client SDK returns the payment code to Mobile Payment Provider app by paymentCodeListener (TheMobile Payment Provider app must implement the IAPConnectPaymentCodeListener protocol to obtain the code).
#pragma mark - IAPConnectPaymentCodeListener
- (void)onPaymentCodeUpdateFailed:(IAPConnectResultCode)resultCode resultMessage:(NSString *)resultMessage {
}
- (void)onPaymentCodeUpdated:(NSString *)paymentCode {
dispatch_async(dispatch_get_main_queue(), ^{
[self.mixedCodeView updatePaymentCode:paymentCode];
});
}
Step 3: Process the payment
Mobile Payment Provider needs to process the payment requests sent from Alipay+ by using the pay API.
Process flow
The API request contains the following fields:
No. | Field | Remarks |
1 | acquirerId | / |
2 | pspId | / |
3 | order | In User-presented Mode Payment, isInStorePayment is |
4 | paymentRequestId | This field is used for the idempotence control. For the payment requests which are initiated with the same paymentRequestId and reach a final status ( |
5 | paymentAmount | The amount that Mobile Payment Provider requests to receive in the currency that A+ uses to create the payment order. If promotion exists, this is the amount that excludes the promotion amount. |
6 | payToAmount | The amount that Mobile Payment Provider settles to Alipay+ in Mobile Payment Provider's currency. When Mobile Payment Provider's currency is different from the merchant's currency, the following equation applies: payToAmount.value=paymentAmount.value*paymentQuote.quotePrice. |
7 | paymentMethod | For User-presented Mode Payment, isInStorePayment is |
8 | paymentFactor | The following rules apply:
|
9 | paymentQuote Optional | Required when paymentAmount is not equal to payToAmount. The value of payToAmount is computed based on values of paymentAmount and paymentQuote, by using a rounding mode of This field is only used when payToAmount.currency is not the same as paymentAmount.currency. |
10 | paymentExpiryTime | Required when payment is required to be successful before the expiration time. |
11 | paymentNotifyUrl Optional | / |
12 | paymentRedirectUrl Optional | / |
13 | paymentPromoInfo Optional | Required when the promotion is applied to the payment. |
14 | surchargeInfo Optional | Required when paymentFactor.needSurcharge is |
17 | passThroughInfo Optional | / |
The API response contains the following field:
No. | Field | Remarks |
1 | result | If result.resultCode is |
4 | paymentId | Must be returned when the payment is successful. |
5 | paymentUrl | / |
6 | paymentTime | Must be returned when the payment is successful. |
7 | paymentAmount Optional | / |
8 | payToAmount Optional | / |
9 | customerId Optional | Must be returned when the payment is successful. |
11 | passThroughInfo Optional |
Processing logic
When processing payment requests, Mobile Payment Provider must pay attention to the following items:
- Use the timeout value assigned by Alipay+, if Alipay+ does not provide the timeout value, for User-presented Mode Payment, set the timeout value as 1 minute at most. When timeout occurs, Mobile Payment Provider closes the payment order and returns an error code
ORDER_IS_CLOSED
. - Mobile Payment Provider must be able to handle payment requests with specified customerId (paymentMethod.customerId).
- Mobile Payment Provider must be able to check the idempotency of payment requests by using paymentRequestId.
- Support all the currencies as defined in ISO 4217.
- Mobile Payment Provider must be able to synchronously return the payment result.
- Exceptional case:
- Check whether the balance is enough. If not, return a result.resultCode of
USER_BALANCE_NOT_ENOUGH
. - Mobile Payment Provider must verify the user status (especially, if user is allowed to login when the account is frozen). if the status is abnormal, return a result.resultCode of
USER_STATUS_ABNORMAL
. - Optional: If the payment is declined for risk reasons, return a result.resultCode of
RISK_REJECT
. - Optional: If the payment failed because the payment method used by the Mobile Payment Provider is not available, return a result.resultCode of
UNAVAILABLE_PAYMENT_METHOD
. - Optional: If the payment is declined because the payment verification is failed, return a result.resultCode of
USER_PAYMENT_VERIFICATION_FAILED
. - Optional: If the payment is declined because the user KYC is failed, return a result.resultCode of
USER_KYC_NOT_QUALIFIED
. - Optional: If the payment is declined because the merchant verification is failed, return a result.resultCode of
MERCHANT_NOT_REGISTERED
.
Payment amount limitation exists
If payment amount limitation exists, Mobile Payment Provider must pay attention to the following items:
- Check whether the amount exceeds the payment amount limit of a single transaction. If yes, return an error code
PAYMENT_AMOUNT_EXCEED_LIMIT
- Check whether the accumulated amount exceeds the limit. If yes, return an error code
USER_AMOUNT_EXCEED_LIMIT
- Check whether the payment times exceed the limit. If yes, return an error code
PAYMENT_COUNT_EXCEED_LIMIT
Promotion exists
If a promotion exists, the amount user actually pays is specified in the payToAmount field.
Sample
Request:
{
"order": {
"referenceOrderId": "OrderID_010101****",
"orderDescription": "SHOES",
"orderAmount": {
"value": "100",
"currency": "JPY"
},
"merchant": {
"referenceMerchantId": "M00xxxxx0001",
"merchantMCC": "1405",
"merchantName": "UGG",
"merchantAddress": {
"region": "JP",
"city": "xxx"
},
"store": {
"referenceStoreId": "S00xxxx0001",
"storeName": "UGG-2",
"storeMCC": "1405"
}
}
},
"acquirerId": "102218800000000****",
"pspId": "102217200000000****",
"paymentRequestId": "201811291907410100070000007****",
"paymentAmount": {
"value": "100",
"currency": "JPY"
},
"paymentMethod": {
"paymentMethodType": "CONNECT_WALLET",
"paymentMethodId": "281006050000000000125733DAHJ****",
"customerId":"2160xxxxxxxxxxx1"
},
"payToAmount": {
"value": "1000",
"currency": "KRW"
},
"paymentQuote": {
"quoteId": "1234567",
"quoteCurrencyPair": "JPY/KRW",
"quotePrice": "10.0000"
},
"paymentFactor": {
"isInStorePayment": "true"
}
}
Response:
{
"result": {
"resultCode":"SUCCESS",
"resultStatus":"S",
"resultMessage":"Success"
},
"paymentId":"201xxxxxxxxxxxxxxxxxxxxxxx4444",
"paymentTime": "2020-01-01T12:01:01+08:30",
"customerId":"1234567"
}
For more information about how to use the API (such as the parameter description), see pay for details.