Guide on redirections between the merchant and the Mobile Payment Provider
1. Overview
For Alipay+ Auto Debit, redirections between the merchant and the Mobile Payment Provider (MPP, normally, a digital wallet) occur during the authorization process.
For Alipay+ Cashier Payment, redirections between the merchant and the MPP occur during the payment process.
This document explains how the redirections work on Android, iOS, and Web sides, and provides best practices on how to handle the redirections in different scenarios.
1.1 Process
This section describes the redirection processes for Auto Debit and Cashier Payment in detail.
1.1.1 Auto Debit
The following figure illustrates the redirection process:
For Auto Debit, redirections occur during the authorization process. See the following list for the process breakdown:
- On the merchant side, the user selects a wallet to authorize. The merchant sends the authorization info to the Acquiring Service Provider (ACQP) (Step 1 - 3).
- The ACQP uses prepare interface to obtain the authorization URL (Step 4 - 10). authRedirectUrl must be included in the request, which is used to redirect the user back to the merchant at the user completes the authorization.
- The merchant system redirects the user to the authorization page specified by the authorization URL (Step 11).
- The wallet system renders the authorization page, where the user completes the authorization (Step 12 - 13).
- The wallet processes the authorization and redirects the user back to the merchant page specified by authRedirectUrl (Step 14 - 16). The authorization code (authCode) is attached in the authRedirectUrl (Step 14 - 16).
- With the authCode, the merchant system uses the applyToken interface to obtain accessToken, which is used to debit funds from the user's authorized wallet (Step 17 - 24).
1.1.2 Cashier Payment
The following figure illustrates the redirection process:
For Cashier Payment, redirections occur during the payment process. See the following list for the process breakdown:
- On the merchant side, the user selects a wallet to pay. The merchant sends the payment order info to the ACQP (Step 1 - 3).
- The ACQP uses the pay interface to send the payment request to Alipay+ (Step 4). paymentRedirectUrl must be included in the request, which is used to redirect the user back to the merchant after the payment is completed.
- Alipay+ processes the request and returns the payment redirection URL to the merchant (Step 5 -9).
- The merchant redirects the user to the cashier page specified by the payment URL, where the user pays (Step 10 - 12).
- The wallet processes the payment and redirects the user back to the merchant page specified by paymentRedirectUrl (Step 14 - 16).
Note:
When the terminal type of the merchant is Web, and if the order code is merchant-rendered QR code, no redirection occurs.
For more information about limitations for redirection, see section 1.2.
1.2 Client type and redirections
For both Auto Debit and Cashier Payment, the redirections always occur in 2 stages:
- The user is redirected from the merchant side to the wallet side.
- The user is redirected from the wallet side back to the merchant side.
For Auto Debit, both redirections must succeed. For Cashier Payment, the second redirection does not affect the payment result.
Furthermore, the merchant client and the wallet client can be either app, WAP, or web. However, redirections can only happen between certain terminal types of client-side. See the following sections for details.
1.2.1 Auto Debit
- Redirection from the merchant to the wallet:
From merchant | To MPP | ||
App | WAP | Web | |
App | ✅ Supported. | ✅ Supported. Used when the MPP app is not available. | N/A |
WAP | Forbidden. The user can be only redirected from the merchant's WAP page to the wallet's WAP page. Otherwise, when redirecting the user back from an app to a WAP page, the user login info might be lost and result in authorization failure. | ✅ Supported. | N/A |
Web | N/A | N/A | ✅ Supported. |
- Redirection from the wallet back to the merchant:
From MPP | To merchant | ||
App | WAP | Web | |
App | ✅ Supported. | N/A The user can only be redirected from the merchant's WAP page to the wallet's WAP page, therefore, the redirection-back from the wallet app to the merchant WAP client will not occur. | N/A |
WAP | ✅ Supported. Used when the MPP app is not available. | ✅ Supported. | N/A |
Web | N/A | N/A | ✅ Supported. |
1.2.2 Cashier Payment
- Redirection from the merchant to the wallet:
From merchant | To MPP | ||
App | WAP | Web | |
App | ✅ Supported. | ✅ Supported. Used when the MPP app is not available. | N/A |
WAP | ✅ Supported. | ✅ Supported. | N/A |
Web | N/A | N/A | ✅ Supported. |
- Redirection from the wallet back to the merchant:
From MPP | To merchant | ||
App | WAP | Web | |
App | ✅ Supported. | ✅ Supported. | N/A |
WAP | ✅ Supported. Used when the MPP app is not available. | ✅ Supported. | N/A |
Web | N/A | N/A | ✅ Supported. |
Note:
When the terminal type of the merchant is Web, and if the order code is merchant-rendered QR code, no redirection occurs.
2. Alipay+ redirection standards
2.1 Basic conceptions
2.1.1 Deep linking
In the context of Web development, deep linking is the use of a hyperlink that links to a specific, generally searchable or indexed, piece of web content on a website (e.g. http://example.com/my-awesome-content-page
), rather than the website's home page (e.g. http://example.com
).
In the context of mobile development, deep linking refers to directly linking to in-app content using a hyperlink.
For Auto Debit, the redirection uses deep linking to redirect the user from the merchant side to the authorization page on the MPP side while retaining the context about the authorization.
For Cashier Payment, the redirection uses deep linking to redirect the user from the merchant side to the payment page on the MPP side, while retaining the context of the payment.
2.1.2 URL scheme, Universal Link, and App Link.
URL scheme, Universal Link, and App Link are ways to realize deep linking.
URL scheme is the part of a URI that specifies the app your device uses to open a URL. In the context of mobile development, URL schemes (more precisely, custom URL schemes) allow users to open your app from other apps or WAP pages. However, the URL scheme has some inherent limitations:
- Errors occur if the app to be opened is not installed.
- You cannot decide which app to open if multiple schemes with the same name are registered.
To solve these problems, iOS uses Universal Link. Android uses App Link. You can visit the pages in the hyperlinks to learn more about them.
2.1.3 Alipay+ URL types
Alipay+ uses schemeUrl, applinkUrl, and normalUrl.
- schemeUrl represents URL schemes.
- applinkUrl represents Universal Links and App Links.
- normalUrl represents the ordinary Web/WAP URL that redirects users to a Web/WAP page.
See section 2.2.1 for details.
2.2 Handle the redirection
2.2.1 Redirection to the wallet
For Cashier Payment, the MPP enables Alipay+ to construct the payment URLs of the types as introduced in section 2.1.3. Alipay+ returns the URL as the paymentUrl field to the merchant.
For Auto Debit, Alipay+ uses the prepare interface to request that the MPP provides the authorization URL. The MPP must construct the URL accordingly. See the prepare interface for details.
For redirections with appLinkUrl, a fallback logic is strongly recommended to be applied by the MPP, to ensure that when the user redirects to the MPP's page by using an appLinkUrl, the MPP's wallet app (if installed) can be invoked.
To achieve that, add the following logic at the appLinkUrl page:
- Check if the webview is Safari of at least iOS 9 or higher. If it is, use the <a> tag for redirection.
- Check if the webview is Android Chrome. If it is, use the intent method for redirection. See intent for details about the method.
- In other scenarios, use the <iframe> tag for redirection.
The logic is illustrated by the figure below:
Sample code:
const ua = window.navigator.userAgent
const isIOS = ua.match(/(iPhone|iPad|iPod)/)
const osVersion = (() => {
const matched = ua.match(/OS ([\d_.]+) like Mac OS X/)
if (matched) {
return matched[1].split('_').join('.')
}
return ''
})()
const isSafari = isIOS && ua.match(/Safari/) && ua.match(/Version\/([\d.]+)/)
function verCompare (a, b) {
const v1 = a.split('.')
const v2 = b.split('.')
for (let i = 0; i < v1.length || i < v2.length; i += 1) {
const n1 = parseInt(v1[i], 10) || 0
const n2 = parseInt(v2[i], 10) || 0
if (n1 < n2) {
return -1
} else if (n1 > n2) {
return 1
}
}
return 0
}
function useAnchorLink (url) {
const doc = window.document
const a = doc.createElement('a')
a.setAttribute('href', url)
a.style.display = 'none'
doc.body.appendChild(a)
const e = doc.createEvent('HTMLEvents')
e.initEvent('click', false, false)
a.dispatchEvent(e)
}
const ios9SafariFix = isIOS && verCompare(osVersion, '9.0') >= 0 && isSafari
let iframe
function callInIframe (url) {
const doc = window.document
if (!iframe) {
iframe = doc.createElement('iframe')
iframe.id = `callapp_iframe_${Date.now()}`
iframe.frameborder = '0'
iframe.style.cssText = 'display:none;border:0;width:0;height:0;'
doc.body.appendChild(iframe)
}
iframe.src = url
}
const isOriginalChrome = (() => {
let isChrome = false
let isWebview = false
const isAndroid = ua.match(/Android[\s/]([\d.]+)/)
if (ua.match(/(?:Chrome|CriOS)\/([\d.]+)/)) {
isChrome = true
if (ua.match(/Version\/[\d+.]+\s*Chrome/)) {
isWebview = true
}
}
return isAndroid && isChrome && !isWebview
})()
const gotoApp = (scheme, packageName) => {
if (isOriginalChrome) {
const protocol = scheme.substring(0, scheme.indexOf('://'))
const hash = `#Intent;scheme=${protocol};package=${packageName};end`
scheme = scheme.replace(/.*?:\/\//, 'intent://')
scheme += hash
}
if (ios9SafariFix) {
useAnchorLink(scheme)
} else if (scheme.indexOf('intent:') === 0) {
window.location.href = scheme
} else {
callInIframe(scheme)
}
}
Note:
The scheme
in the sample code is the wallet's schemeURL, the packageName
is the wallet's app
package name.
// demo
gotoApp('yourscheme://goto', 'android.package.name')
2.2.2 Redirection back to the merchant
The fields for redirection back to the merchant are provided in the interface request, specifically:
- authRedirectUrl for Auto Debit, in the prepare interface request.
- paymentRedirectUrl for Cashier Payment, in the pay interface request.
The MPP must be able to handle all the URLs from the merchant, which includes 3 types according to the merchant side environment, specifically:
- If the merchant side is the merchant's app, schemeUrl or applinkUrl is used.
- If the merchant side is browsers or other apps, applinkUrl or normalUrl is used.
2.2.2.1 From iOS app
Try opening the merchant app with schemeUrl, universal link, and normalUrl. For the priority of these URLs, schemeUrl > applinkUrl > normalUrl.
Note:
To use the schemeUrl, the wallet app must add the merchant app in the allowlist. So the schemeUrl is suitable for scenarios where the merchant information is available to the wallet.
To add the merchant app's scheme into the allowlist, add LSApplicationQueriesSchemes and set the scheme of the target app into the wallet app's Info.plist file, as described by the figure below:
Sample code:
// Place following code for init webView to right place.
// self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
// [self.view addSubview:_webView];
NSString *applinkUrl = @"Your AppLinkUrl";
NSString *schemeUrl = @"Your SchemeUrl";
NSString *normalUrl = @"Your NormalUrl";
UIApplication *application = [UIApplication sharedApplication];
if ([application canOpenURL:[NSURL URLWithString:schemeUrl]]) {
if (@available(iOS 10.0, *)) {
[application openURL:[NSURL URLWithString:schemeUrl] options:@{} completionHandler:^(BOOL success) {
if (success) {
// do something.
}
}];
} else {
[application openURL:[NSURL URLWithString:schemeUrl]];
}
} else if ([application canOpenURL:[NSURL URLWithString:applinkUrl]]) {
// applink.
if (@available(iOS 10.0, *)) {
[application openURL:[NSURL URLWithString:applinkUrl] options:@{UIApplicationOpenURLOptionUniversalLinksOnly: @YES} completionHandler:^(BOOL success) {
if (success) {
// do something.
} else {
// Can't open universal link directly, it might not install related App.
NSURL *url = [NSURL URLWithString:applinkUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}
}];
} else {
NSURL *url = [NSURL URLWithString:applinkUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}
} else {
// normal url.
NSURL *url = [NSURL URLWithString:normalUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}
2.2.2.2 From Android app
Use the logic below for the redirection-back from Android apps:
Intent intent = new Intent(Intent.ACTION_VIEW, authUri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//If you know the merchant app name, set the package name with it
intent.setPackage(packageName)
contex.startActivity(intent);
2.2.2.3 From WAP/Web
When redirects back from the wallet WAP/Web page:
- Check if the merchant page URL starts with
https
/http
. If it is, redirect directly. - Check if the webview is Safari of at least iOS 9 or higher. If it is, use the <a> tag for redirection.
- In other scenarios, use the <iframe> tag for redirection.
Sample code:
const ua = window.navigator.userAgent
const isIOS = ua.match(/(iPhone|iPad|iPod)/)
const osVersion = (() => {
const matched = ua.match(/OS ([\d_.]+) like Mac OS X/)
if (matched) {
return matched[1].split('_').join('.')
}
return ''
})()
const isSafari = isIOS && ua.match(/Safari/) && ua.match(/Version\/([\d.]+)/)
function verCompare (a, b) {
const v1 = a.split('.')
const v2 = b.split('.')
for (let i = 0; i < v1.length || i < v2.length; i += 1) {
const n1 = parseInt(v1[i], 10) || 0
const n2 = parseInt(v2[i], 10) || 0
if (n1 < n2) {
return -1
} else if (n1 > n2) {
return 1
}
}
return 0
}
function useAnchorLink (url) {
const doc = window.document
const a = doc.createElement('a')
a.setAttribute('href', url)
a.style.display = 'none'
doc.body.appendChild(a)
const e = doc.createEvent('HTMLEvents')
e.initEvent('click', false, false)
a.dispatchEvent(e)
}
const ios9SafariFix = isIOS && verCompare(osVersion, '9.0') >= 0 && isSafari
let iframe
function callInIframe (url) {
const doc = window.document
if (!iframe) {
iframe = doc.createElement('iframe')
iframe.id = `callapp_iframe_${Date.now()}`
iframe.frameborder = '0'
iframe.style.cssText = 'display:none;border:0;width:0;height:0;'
doc.body.appendChild(iframe)
}
iframe.src = url
}
const gotoApp = url => {
// appLink direct redirection
if (/^(http|https):\/\//.test(url)) {
window.location.href = url
}
if (ios9SafariFix) {
useAnchorLink(url)
} else {
callInIframe(url)
}
}
Test code:
// Applink
gotoApp('http://test.com')
// Scheme
gotoApp('test://xxx')