PayPay Smart Payment is a password-free payment JS SDK launched by PayPay, dedicated to optimizing the buyer's payment experience and improving payment success rates. It allows you to integrate PayPay's features into your user interface. After obtaining the buyer's authorization, subsequent payments can be completed without redirecting to the PayPay app. The user experience for the first payment and subsequent payments is as follows:
For the first payment, buyers need to log in to PayPay for authorization. After successful authorization, buyers will be redirected to the merchant's page to complete the payment. For subsequent payments, the PayPay wallet app will not be launched, and the payment will be completed directly on the merchant's side. User experience comparison
There is no difference in the user experience for the first payment and subsequent payments when integrated on the Web/WAP side. However, there are slight differences on mobile, as stated in the following table:
The following are flow chart for the first payment and subsequent payment:
Before you start integrating, read the Integration Guide and API Overview documents to understand the integration steps of the server-side API and the precautions for calling the API. Furthermore, ensure that the following prerequisites are met: - Obtain a client ID
- Complete the key configuration
- Complete the configuration of paymentNotifyUrl to receive the asynchronous notification
- Integrate the server-side SDK package, install the server-side library, and initialize a request instance. For more details, refer to Server-side SDKs.
To ensure compatibility and security in the payment process, the following lists the minimum version requirements for various browsers and applications. In particular, merchant WebViews and the PayPay app must run on the specified system versions or higher. - Browser version requirement:
- The merchant WebView must support iOS 11 or later, and Android 4.4 (API level 19) or later.
- The PayPay app must run on iOS 16 or later, and Android 9 or later.
Start your integration by taking the following steps:
- Create a payment order
- Get the payment continuation URL
- Receive the asynchronous notification
Step 1: Create a payment order
Server-side
Call the pay (One-time Payments) API. Specify paymentMethod.paymentMethodType as PAYPAY
in the request, and set paymentMethod.paymentMethodMetadata.smartPaymentEnabled to true
. Note:
- Both the first payment and subsequent payments require calling the pay (One-time Payments) API and redirecting to the returned normalUrl.
- The paymentRedirectUrl provided by the merchant must start with https://.
{
"order": {
"env": {
"osType": "IOS",
"terminalType": "APP"
},
"orderAmount": {
"currency": "JPY",
"value": "1825"
},
"orderDescription": "TEST.COM",
"referenceOrderId": "TEST4754300929"
},
"paymentAmount": {
"currency": "JPY",
"value": "1825"
},
"paymentMethod": {
"paymentMethodMetadata": "{"smartPaymentEnabled":true}",
"paymentMethodType": "PAYPAY"
},
"paymentNotifyUrl": "https://www.yourwebsite.com/notify/channel/notify",
"paymentRedirectUrl": "https://www.yourwebsite.com/redirect",
"paymentRequestId": "TEST4754300929",
"productCode": "CASHIER_PAYMENT",
"settlementStrategy": {
"settlementCurrency": "JPY"
}
}
After receiving the request, Antom will return the corresponding PayPay payment continuation URL (normalUrl). Example code is as follows: {
"normalUrl": "https://ac.alipay.com/page/antom-web-checkout-v2/payment-transition/pages/paypay/index.html?orderInfo=***test",
"paymentActionForm": "{"method":"GET","paymentActionFormType":"RedirectActionForm","redirectUrl":"https://ac.alipay.com/page/antom-web-checkout-v2/payment-transition/pages/paypay/index.html?orderInfo=***test"}",
"paymentAmount": {
"currency": "JPY",
"value": "1825"
},
"paymentCreateTime": "2025-09-16T20:48:47-07:00",
"paymentId": "20250917******450216341557",
"paymentRequestId": "PAYMENT_202*****46357_AUTO",
"redirectActionForm": {
"method": "GET",
"redirectUrl": "https://ac.alipay.com/page/antom-web-checkout-v2/payment-transition/pages/paypay/index.html?orderInfo=***test"
},
"result": {
"resultCode": "PAYMENT_IN_PROCESS",
"resultMessage": "payment in process",
"resultStatus": "U"
}
}
Step 2: Get the payment continuation URL
Client-side
After getting the payment continuation URL returned by Antom, the merchant server passes the address to the front end. The merchant front end redirects to the PayPay page. The different types of payment continuation URL are shown as follows: For Web and WAP, you can directly redirect to the normalUrl. Example code is as follows:
window.location.href = pay.response.normalUrl;
Note: Only redirect to the normalUrl. Antom will determine whether to display the payment authorization page (for the first payment) or a half-screen payment confirmation page (for subsequent payments) based on whether the user has stored payment information in the browser.
Process the payment continuation URL (normalUrl) returned by Antom according to the following steps:
For iOS, you cannot directly redirect to the normalUrl. You need to append the parameter source=embedded to the normalUrl and then load it using a WebView, as shown in the following example:
https://ac.alipay.com/page/antom-web-checkout-v2/payment-transition/pages/paypay/index.html?orderInfo=Y2xpZW50SWQ9YV90M0I0ZERrRG1HJm1lcmNoYW50SWQ9MTg4QzBFR2tQWlhhRDN4dHFMZXVuRFM4UXdpbXU4YWR2V09Pc2VycFpWcWE3bz0mcGF5bWVudFJlcXVlc3RJZD1oNWtnZDdyQ0U0Nm91ZDJjdHhVcE5MSzZjOUpwRkR6M2VLVEsyTDQ0bFBjPSZtZXJjaGFudEFsaWFzPTkxODQ2MDc2MDQyMDU1NjgwMCZjaGFubmVsUGF5bWVudElkPTc0ODE3MjczNjM0NTYzJmFtb3VudD0zMDAmY3VycmVuY3k9SlBZJm1lcmNoYW50UmVkaXJlY3RVcmw9aHR0cHMlM0ElMkYlMkZwc3AuYWMuYWxpcGF5LmNvbSUyRnBhZ2UlMkZzaW11bGF0aW9uLXdhbGxldCUyRmFjd2FsbGV0JTJGYWxpcGF5Y29ubmVjdGNvZGUuaHRtbCZwYXltZW50UmVkaXJlY3RVcmw9aHR0cHMlM0ElMkYlMkZvcGVuLW5hLmFsaXBheS5jb20lMkZhcGklMkZvcGVuJTJGdXJsX2NhbGxiYWNrX3Nob3J0X2dldCUyRnNicHMlMkZ1cmxDYWxsYmFjay5odG0lM0ZzaWduRGF0YSUzREZFZDBhRGN6VHp6WTVzSlo3NVNtV3ZSUTRRcyUyNTNEJTI2aW5TZXJpYWxObyUzRDIwMjUwOTE3ODkwMzEzMDAwMDg1NTYxMTU1NDM2NTYlMjZvdXRPcmRlck5vJTNENzQ4MTcyNzM2MzQ1NjM=®ion=SG&source=embedded
2. WebView interception and external navigation
The WebView loads the normalUrl (the Antom intermediate page), while intercepting the redirected PayPay linkUrl to externally launch the PayPay app or page. Note: If you need to use the PayPay test wallet, please contact Antom technical support for additional registration. - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURL *url = navigationAction.request.URL;
NSString *urlString = url.absoluteString;
if ([urlString containsString:@"antom_sanbox"]) {
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
NSMutableDictionary *queryParameters = [NSMutableDictionary dictionary];
// Check if the URL has query items
if (components.queryItems) {
// Iterate through all query items
for (NSURLQueryItem *item in components.queryItems) {
if (item.value) {
// Add parameter name and value to the dictionary
queryParameters[item.name] = item.value;
}
}
}
NSString *isDeeplinkUrl = queryParameters[@"isDeeplinkUrl"];
if (isDeeplinkUrl && [isDeeplinkUrl length] > 0 && [isDeeplinkUrl isEqualToString:@"true"]) {
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
}
if ([urlString containsString:@"www.sandbox.paypay"] || [urlString containsString:@"www.paypay.ne.jp"]) {
NSLog(@"Intermediate page");
NSLog(@"Merchant handles the subsequent logic");
if (url) {
// Use UIApplication.shared.open to open the URL
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
}
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
3. Perform a secondary redirect after obtaining the paypayRedirectUrl and one_time_token
Obtain the paypayRedirectUrl and one_time_token after PayPay redirects back to the merchant URL.
After completing the authorization, the buyer is redirected back to the merchant's paymentRedirectUrl and PayPay appends the paypayRedirectUrl and one_time_token parameters to this URL to perform a secondary redirect, as shown in the following example: https://www.yourwebsite.com/ltspc/pay/callback/deeplink?paypayRedirectUrl=https%253A%252F%252Fac.alipay.com%252Fpage%252Fantom-web-checkout-v2%252Fpayment-transition%252Fpages%252Fpaypay%252Findex.html%253ForderInfo%253DY2xpZW50SWQ9YV90M0I0ZERrRG1HJm1lcmNoYW50SWQ9MTg4QzBFR2tQWlhhRDN4dHFMZXVuRFM4UXdpbXU4YWR2V09Pc2VycFpWcWE3bz0mcGF5bWVudFJlcXVlc3RJZD1wemFtMXk1NWlCWXdnVDhNQUpFK0tYVjlyMDQ5L0ZFQjBSY01DUWpXMlhvPSZtZXJjaGFudEFsaWFzPTkxODQ2MDc2MDQyMDU1NjgwMCZjaGFubmVsUGF5bWVudElkPTUwMzg1MzA0MzM2OTMxJmFtb3VudD0xMCZjdXJyZW5jeT1KUFkmbWVyY2hhbnRSZWRpcmVjdFVybD1odHRwcyUzQSUyRiUyRnByZS5hYy5hbGlwYXkuY29tJTJGcGFnZSUyRmFudG9tX3NhbmJveCUyRnJlZGlyZWN0Lmh0bWwlM0Z1cmwlM0RrYWRlbW8lM0ElMkYlMkZzZXR0aW5nJTJGcGF0aCUyNmF1dG8lM0QwJnBheW1lbnRSZWRpcmVjdFVybD1odHRwcyUzQSUyRiUyRm9wZW4tbmEuYWxpcGF5LmNvbSUyRmFwaSUyRm9wZW4lMkZ1cmxfY2FsbGJhY2tfc2hvcnRfZ2V0JTJGc2JwcyUyRnVybENhbGxiYWNrLmh0bSUzRnNpZ25EYXRhJTNEM0gxUVpFRUNFSzNMSkRkUnBCZm5XaWpSZnFvJTI1M0QlMjZpblNlcmlhbE5vJTNEMjAyNTEwMjM4OTAzMTMwMDAwOTc2OTYxNTM1MjkxNiUyNm91dE9yZGVyTm8lM0Q1MDM4NTMwNDMzNjkzMQ%25253D%25253D%2526region%253DSG%2526source%253Dembedded%2526isAuthorized%253Dtrue&one_time_token=2bdae7ec-9d3a-4636-9662-05fbdcf3e9f6&ppSmartPayment=1
Example code for extracting the two parameters paypayRedirectUrl and one_time_token and decoding the URL:
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
NSURL *url = userActivity.webpageURL;
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
// Replace with the host from paymentRedirectUrl
if ([components.host isEqualToString:@"psp.ac.alipay.com"]) {
NSMutableDictionary *queryParameters = [NSMutableDictionary dictionary];
// Check if the URL has query items
if (components.queryItems) {
// Iterate through all query items
for (NSURLQueryItem *item in components.queryItems) {
if (item.value) {
// Add parameter name and value to the dictionary
queryParameters[item.name] = item.value;
}
}
}
NSString *paypayRedirectUrl = queryParameters[@"paypayRedirectUrl"];
if (paypayRedirectUrl && [paypayRedirectUrl length] > 0) {
paypayRedirectUrl = [paypayRedirectUrl stringByRemovingPercentEncoding];
// Concatenate PayPay parameters
NSString *refreshUrl = [NSString stringWithFormat:@"%@&one_time_token=%@&ppSmartPayment=1", queryParameters[@"paypayRedirectUrl"], queryParameters[@"one_time_token"]];
// Refresh or open the payment page, this payment page will not launch the paypay app
}
}
return true;
}
When the merchant's intermediate page launches the merchant application, ensure the paypayRedirectUrl and one_time_token parameters are not lost. After obtaining the URL requiring secondary redirection, you can reload this URL via WebView (as noted in the comment on line 25 of the code). The following example shows an URL requiring secondary redirection, where one_time_token has already been appended after paypayRedirectUrl:
Note: For the first payment after successful authorization, PayPay needs to append both paypayRedirectUrl and one_time_token parameters. Subsequent payments will not include these parameters, so PayPay does not need to append them to the link. https://ac.alipay.com/page/antom-web-checkout-v2/payment-transition/pages/paypay/index.html?orderInfo=Y2xpZW50SWQ9YV90M0I0ZERrRG1HJm1lcmNoYW50SWQ9MTg4QzBFR2tQWlhhRDN4dHFMZXVuRFM4UXdpbXU4YWR2V09Pc2VycFpWcWE3bz0mcGF5bWVudFJlcXVlc3RJZD1wemFtMXk1NWlCWXdnVDhNQUpFK0tlMlY1MVh6eSt2TWxMd2V3NlYrN0s0PSZtZXJjaGFudEFsaWFzPTkxODQ2MDc2MDQyMDU1NjgwMCZjaGFubmVsUGF5bWVudElkPTUwMzg1NTQwMTY1MjUwJmFtb3VudD0xMCZjdXJyZW5jeT1KUFkmbWVyY2hhbnRSZWRpcmVjdFVybD1odHRwcyUzQSUyRiUyRnByZS5hYy5hbGlwYXkuY29tJTJGcGFnZSUyRmFudG9tX3NhbmJveCUyRnJlZGlyZWN0Lmh0bWwlM0Z1cmwlM0RrYWRlbW8lM0ElMkYlMkZzZXR0aW5nJTJGcGF0aCUyNmF1dG8lM0QwJnBheW1lbnRSZWRpcmVjdFVybD1odHRwcyUzQSUyRiUyRm9wZW4tbmEuYWxpcGF5LmNvbSUyRmFwaSUyRm9wZW4lMkZ1cmxfY2FsbGJhY2tfc2hvcnRfZ2V0JTJGc2JwcyUyRnVybENhbGxiYWNrLmh0bSUzRnNpZ25EYXRhJTNEQUhrTVdMOHpUd1clMjUyQmtXcGNFaG14UHJrSHk0SSUyNTNEJTI2aW5TZXJpYWxObyUzRDIwMjUxMDIzODkwMzEzMDAwMDkxNDEzMjAyNDY0OTYlMjZvdXRPcmRlck5vJTNENTAzODU1NDAxNjUyNTA%3D®ion=SG&source=embedded&isAuthorized=true&one_time_token=4f4c7877-553b-438c-9739-d64109a2bd66&ppSmartPayment=1
After payment completion, the system will redirect back to the merchant's original paymentRedirectUrl. At this point, the H5 page will display the payment result based on the server response, with no additional parameters appended to the paymentRedirectUrl.
Process the payment continuation URL (normalUrl) returned by Antom according to the following steps:
For iOS, you cannot directly redirect to the normalUrl. You need to append the parameter source=embedded to the normalUrl and then load it using a WebView, as shown in the following example:
https://ac.alipay.com/page/antom-web-checkout-v2/payment-transition/pages/paypay/index.html?orderInfo=Y2xpZW50SWQ9YV90M0I0ZERrRG1HJm1lcmNoYW50SWQ9MTg4QzBFR2tQWlhhRDN4dHFMZXVuRFM4UXdpbXU4YWR2V09Pc2VycFpWcWE3bz0mcGF5bWVudFJlcXVlc3RJZD1oNWtnZDdyQ0U0Nm91ZDJjdHhVcE5MSzZjOUpwRkR6M2VLVEsyTDQ0bFBjPSZtZXJjaGFudEFsaWFzPTkxODQ2MDc2MDQyMDU1NjgwMCZjaGFubmVsUGF5bWVudElkPTc0ODE3MjczNjM0NTYzJmFtb3VudD0zMDAmY3VycmVuY3k9SlBZJm1lcmNoYW50UmVkaXJlY3RVcmw9aHR0cHMlM0ElMkYlMkZwc3AuYWMuYWxpcGF5LmNvbSUyRnBhZ2UlMkZzaW11bGF0aW9uLXdhbGxldCUyRmFjd2FsbGV0JTJGYWxpcGF5Y29ubmVjdGNvZGUuaHRtbCZwYXltZW50UmVkaXJlY3RVcmw9aHR0cHMlM0ElMkYlMkZvcGVuLW5hLmFsaXBheS5jb20lMkZhcGklMkZvcGVuJTJGdXJsX2NhbGxiYWNrX3Nob3J0X2dldCUyRnNicHMlMkZ1cmxDYWxsYmFjay5odG0lM0ZzaWduRGF0YSUzREZFZDBhRGN6VHp6WTVzSlo3NVNtV3ZSUTRRcyUyNTNEJTI2aW5TZXJpYWxObyUzRDIwMjUwOTE3ODkwMzEzMDAwMDg1NTYxMTU1NDM2NTYlMjZvdXRPcmRlck5vJTNENzQ4MTcyNzM2MzQ1NjM=®ion=SG&source=embedded
2. WebView interception and external navigation
The WebView loads the normalUrl (the Antom intermediate page), while intercepting the redirected PayPay linkUrl to externally launch the PayPay app or page. Note: If you need to use the PayPay test wallet, please contact Antom technical support for additional registration. public class WebViewActivity extends AppCompatActivity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo_web_view);
webView = findViewById(R.id.webView);
webView.setWebViewClient(new MyWebViewClient());
}
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
String url = "";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
url = request.getUrl().toString();
} else {
url = request.toString();
}
Uri parsedUri = Uri.parse(url);
if (parsedUri.toString().contains("antom_sanbox")) {
Bundle queryParameters = new Bundle();
for (String key : parsedUri.getQueryParameterNames()) {
queryParameters.putString(key, parsedUri.getQueryParameter(key));
}
boolean isDeeplinkUrl = Objects.equals(queryParameters.getString("isDeeplinkUrl"), "true");
if (isDeeplinkUrl) {
// Open link in external browser
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
}
}
if (url.contains("www.sandbox.paypay") || url.contains("www.paypay.ne.jp") {
Log.d(TAG, "Intermediate page");
Log.d(TAG, "Merchant handles the subsequent logic");
try {
Intent intent = new Intent(Intent.ACTION_VIEW, parsedUri);
startActivity(intent);
} catch (Exception e) {
// e.printStackTrace();
}
return true;
}
return false;
}
}
}
3. Perform a secondary redirect after obtaining the paypayRedirectUrl and one_time_token
Obtain the paypayRedirectUrl and one_time_token after PayPay redirects back to the merchant URL.
After completing the authorization, the buyer is redirected back to the merchant'spaymentRedirectUrl and PayPay appends the paypayRedirectUrl and one_time_token parameters to this URL to perform a secondary redirect, as shown in the following example: https://www.yourwebsite.com/ltspc/pay/callback/deeplink?paypayRedirectUrl=https%253A%252F%252Fac.alipay.com%252Fpage%252Fantom-web-checkout-v2%252Fpayment-transition%252Fpages%252Fpaypay%252Findex.html%253ForderInfo%253DY2xpZW50SWQ9YV90M0I0ZERrRG1HJm1lcmNoYW50SWQ9MTg4QzBFR2tQWlhhRDN4dHFMZXVuRFM4UXdpbXU4YWR2V09Pc2VycFpWcWE3bz0mcGF5bWVudFJlcXVlc3RJZD1wemFtMXk1NWlCWXdnVDhNQUpFK0tYVjlyMDQ5L0ZFQjBSY01DUWpXMlhvPSZtZXJjaGFudEFsaWFzPTkxODQ2MDc2MDQyMDU1NjgwMCZjaGFubmVsUGF5bWVudElkPTUwMzg1MzA0MzM2OTMxJmFtb3VudD0xMCZjdXJyZW5jeT1KUFkmbWVyY2hhbnRSZWRpcmVjdFVybD1odHRwcyUzQSUyRiUyRnByZS5hYy5hbGlwYXkuY29tJTJGcGFnZSUyRmFudG9tX3NhbmJveCUyRnJlZGlyZWN0Lmh0bWwlM0Z1cmwlM0RrYWRlbW8lM0ElMkYlMkZzZXR0aW5nJTJGcGF0aCUyNmF1dG8lM0QwJnBheW1lbnRSZWRpcmVjdFVybD1odHRwcyUzQSUyRiUyRm9wZW4tbmEuYWxpcGF5LmNvbSUyRmFwaSUyRm9wZW4lMkZ1cmxfY2FsbGJhY2tfc2hvcnRfZ2V0JTJGc2JwcyUyRnVybENhbGxiYWNrLmh0bSUzRnNpZ25EYXRhJTNEM0gxUVpFRUNFSzNMSkRkUnBCZm5XaWpSZnFvJTI1M0QlMjZpblNlcmlhbE5vJTNEMjAyNTEwMjM4OTAzMTMwMDAwOTc2OTYxNTM1MjkxNiUyNm91dE9yZGVyTm8lM0Q1MDM4NTMwNDMzNjkzMQ%25253D%25253D%2526region%253DSG%2526source%253Dembedded%2526isAuthorized%253Dtrue&one_time_token=2bdae7ec-9d3a-4636-9662-05fbdcf3e9f6&ppSmartPayment=1
Example code for extracting the two parameters paypayRedirectUrl and one_time_token and decoding the URL:
/**
* Called when the Activity receives a new Intent
* @param intent The new Intent
*/
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (Intent.ACTION_VIEW.equals(intent.getAction())) {
Uri uri = intent.getData();
if (uri == null) {
return;
}
if (uri.getHost() == null) {
return;
}
// Replace with the host from paymentRedirectUrl
if ( uri.getHost().equals("psp.ac.alipay.com")) {
Bundle queryParameters = new Bundle();
// Iterate through all query parameters
for (String key : uri.getQueryParameterNames()) {
// Add parameter name and value to the dictionary
queryParameters.putString(key, uri.getQueryParameter(key));
}
String paypayRedirectUrl = queryParameters.getString("paypayRedirectUrl");
if (queryParameters.getString("paypayRedirectUrl") != null&& !Objects.requireNonNull(paypayRedirectUrl).isEmpty()) {
try {
// Concatenate PayPay parameters
String paypayRedirectUrl = queryParameters.getString("paypayRedirectUrl");
String decodedUriString = URLDecoder.decode(paypayRedirectUrl, "UTF-8");
String refreshUrl = decodedUriString + "&one_time_token=" + queryParameters.getString("one_time_token") + "&ppSmartPayment=1";
// Refresh or open the payment page, this payment page will not launch the paypay app
} catch (Exception e) {
Log.d(TAG, "handleIntent: ", e);
}
}
}
}
}
When the merchant's intermediate page launches the merchant application, ensure the paypayRedirectUrl and one_time_token parameters are not lost. After obtaining the URL requiring secondary redirection, you can reload this URL via WebView (as noted in the comment on line 25 of the code). The following example shows an URL requiring secondary redirection, where one_time_token has already been appended after paypayRedirectUrl:
Note: For the first payment after successful authorization, PayPay needs to append both paypayRedirectUrl and one_time_token parameters. Subsequent payments will not include these parameters, so PayPay does not need to append them to the URL. https://ac.alipay.com/page/antom-web-checkout-v2/payment-transition/pages/paypay/index.html?orderInfo=Y2xpZW50SWQ9YV90M0I0ZERrRG1HJm1lcmNoYW50SWQ9MTg4QzBFR2tQWlhhRDN4dHFMZXVuRFM4UXdpbXU4YWR2V09Pc2VycFpWcWE3bz0mcGF5bWVudFJlcXVlc3RJZD1wemFtMXk1NWlCWXdnVDhNQUpFK0tlMlY1MVh6eSt2TWxMd2V3NlYrN0s0PSZtZXJjaGFudEFsaWFzPTkxODQ2MDc2MDQyMDU1NjgwMCZjaGFubmVsUGF5bWVudElkPTUwMzg1NTQwMTY1MjUwJmFtb3VudD0xMCZjdXJyZW5jeT1KUFkmbWVyY2hhbnRSZWRpcmVjdFVybD1odHRwcyUzQSUyRiUyRnByZS5hYy5hbGlwYXkuY29tJTJGcGFnZSUyRmFudG9tX3NhbmJveCUyRnJlZGlyZWN0Lmh0bWwlM0Z1cmwlM0RrYWRlbW8lM0ElMkYlMkZzZXR0aW5nJTJGcGF0aCUyNmF1dG8lM0QwJnBheW1lbnRSZWRpcmVjdFVybD1odHRwcyUzQSUyRiUyRm9wZW4tbmEuYWxpcGF5LmNvbSUyRmFwaSUyRm9wZW4lMkZ1cmxfY2FsbGJhY2tfc2hvcnRfZ2V0JTJGc2JwcyUyRnVybENhbGxiYWNrLmh0bSUzRnNpZ25EYXRhJTNEQUhrTVdMOHpUd1clMjUyQmtXcGNFaG14UHJrSHk0SSUyNTNEJTI2aW5TZXJpYWxObyUzRDIwMjUxMDIzODkwMzEzMDAwMDkxNDEzMjAyNDY0OTYlMjZvdXRPcmRlck5vJTNENTAzODU1NDAxNjUyNTA%3D®ion=SG&source=embedded&isAuthorized=true&one_time_token=4f4c7877-553b-438c-9739-d64109a2bd66&ppSmartPayment=1
After payment completion, the system will redirect back to the merchant's original paymentRedirectUrl. At this point, the H5 page will display the payment result based on the server response, with no additional parameters appended to the paymentRedirectUrl.
Note:
- The payment process must ensure a successful return from PayPay to the original browser page. If it fails to return to the original browser, the payment will not be completed.
- When the buyer visits the store and makes subsequent purchases using the same device and browser as the initial payment, and the browser cookies have not been cleared within 395 days, payment can be made without logging in again during this period. If more than 395 days have passed since the last purchase or if the device or browser is changed, the buyer will need to log in again.
- Incognito (private) mode does not support subsequent login-free payments.
- During subsequent payment processes, the PayPay account must not be changed; otherwise, the transaction cannot proceed.
Step 3: Receive the asynchronous notification
Server-side
When a payment is completed or fails, Antom sends an asynchronous notification (notifyPayment) to the address that you specified in the pay (One-time Payments) API via the paymentNotifyUrl parameter. Refer to Receive the asynchronous notification for detailed operations.
The first payment will return both authorization and payment results, while subsequent payments will only return payment results. The following are common scenarios: Antom provides the capability to send asynchronous notifications and also supports actively querying payment results by calling the inquiryPayment API. Example code for asynchronous payment success notification:
{
"actualPaymentAmount": {
"currency": "JPY",
"value": "10"
},
"notifyType": "PAYMENT_RESULT",
"paymentAmount": {
"currency": "JPY",
"value": "10"
},
"paymentCreateTime": "2025-11-04T03:03:23-08:00",
"paymentId": "20251104194010800100188370226536257",
"paymentRequestId": "PAYMENT_20251104190322542_AUTO",
"paymentResultInfo": {},
"paymentTime": "2025-11-04T03:07:20-08:00",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}
Example code for asynchronous payment failure notification:
{
"actualPaymentAmount": {
"currency": "JPY",
"value": "10"
},
"notifyType": "PAYMENT_RESULT",
"paymentAmount": {
"currency": "JPY",
"value": "10"
},
"paymentCreateTime": "2025-10-21T19:30:26-07:00",
"paymentId": "20251022194010800100188520223208649",
"paymentRequestId": "PAYMENT_20251022103025254_AUTO",
"result": {
"resultCode": "ORDER_IS_CLOSED",
"resultMessage": "The order is closed.",
"resultStatus": "F"
}
}
Depending on whether the buyer has installed the PayPay app on their mobile device, the system will provide different subsequent operations: - If the buyer has installed the PayPay app, you can choose to redirect externally to launch the PayPay app. For details, refer to the solution above.
- If the buyer does not have installed the PayPay app, you can adopt the WebView in-app redirection process. For details, refer to the best practices below.
The following code demonstrates how an iOS application uses a WebView to load web pages and intelligently handle redirection logic based on different payment scenarios.
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURL *url = navigationAction.request.URL;
NSString *urlString = url.absoluteString;
// Use Antom sandbox environment wallet, choose one between this and PayPay sandbox environment wallet
if ([urlString containsString:@"antom_sanbox"]) {
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
NSMutableDictionary *queryParameters = [NSMutableDictionary dictionary];
// Check if the URL has query items
if (components.queryItems) {
// Go through all query items
for (NSURLQueryItem *item in components.queryItems) {
if (item.value) {
// Add parameter name and value to the dictionary
queryParameters[item.name] = item.value;
}
}
}
NSString *isDeeplinkUrl = queryParameters[@"isDeeplinkUrl"];
if (isDeeplinkUrl && [isDeeplinkUrl length] > 0 && isDeeplinkUrl == @"true") {
NSURL *sandboxUrl = [NSURL URLWithString:@"alipayconnect://"];
if (sandboxUrl && [[UIApplication sharedApplication] canOpenURL:sandboxUrl]) {
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
decisionHandler(WKNavigationActionPolicyCancel);
return;
} else {
decisionHandler(WKNavigationActionPolicyAllow);
return;
}
}
}
// Use PayPay sandbox environment wallet, choose one between this and Antom sandbox environment wallet
if (([urlString containsString:@"www.sandbox.paypay"] || [urlString containsString:@"www.paypay.ne.jp"])) {
if (url && [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"paypay://"]]) {
// Use UIApplication.shared.open to open the URL
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
decisionHandler(WKNavigationActionPolicyCancel);
return;
} else {
decisionHandler(WKNavigationActionPolicyAllow);
return;
}
}
// Replace with the host from paymentRedirectUrl
if ([urlString containsString:@"psp.ac.alipay.com"]) {
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
NSMutableDictionary *queryParameters = [NSMutableDictionary dictionary];
// Check if the URL has query items
if (components.queryItems) {
// Go through all query items
for (NSURLQueryItem *item in components.queryItems) {
if (item.value) {
// Add parameter name and value to the dictionary
queryParameters[item.name] = item.value;
}
}
}
NSString *paypayRedirectUrl = queryParameters[@"paypayRedirectUrl"];
if (paypayRedirectUrl && [paypayRedirectUrl length] > 0) {
paypayRedirectUrl = [paypayRedirectUrl stringByRemovingPercentEncoding];
// Concatenate PayPay parameters, refresh or open the payment page
NSString *refreshUrl = [NSString stringWithFormat:@"%@&one_time_token=%@&ppSmartPayment=1", queryParameters[@"paypayRedirectUrl"], queryParameters[@"one_time_token"]];
decisionHandler(WKNavigationActionPolicyCancel);
// Refresh or open the payment page, this payment page will not launch the PayPay app
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:refreshUrl]];
[self.webView loadRequest:request];
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
In addition to using the code above to determine whether the payment app is installed, you also need to add the LSApplicationQueriesSchemes parameter to the Info.plist configuration file to declare the URL schemes that can be queried.
Note: The number of schemes that can be configured in Info.plist is limited.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>paypay</string>
<string>alipayconnect</string>
</array>
</dict>
</plist>
The following code demonstrates how an Android application uses a WebView to load web pages and intelligently handle redirection logic based on different payment scenarios.
public class WebViewActivity extends AppCompatActivity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo_web_view);
webView = findViewById(R.id.webView);
webView.setWebViewClient(new MyWebViewClient());
}
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
String url = "";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
url = request.getUrl().toString();
} else {
url = request.toString();
}
Uri parsedUri = Uri.parse(url);
// Use Antom sandbox environment wallet, choose one between this and PayPay sandbox environment wallet
if (parsedUri.toString().contains("antom_sanbox")) {
Bundle queryParameters = new Bundle();
for (String key : parsedUri.getQueryParameterNames()) {
queryParameters.putString(key, parsedUri.getQueryParameter(key));
}
boolean isDeeplinkUrl = Objects.equals(queryParameters.getString("isDeeplinkUrl"), "true");
if (isDeeplinkUrl) {
Intent schemeIntent = createSchemeIntent("alipayconnect://platformapi");
if (schemeIntent != null && isAppIsInstalled(schemeIntent)) {
// Open link in external browser
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
} else {
webView.loadUrl(url);
}
return true;
}
}
// Use PayPay sandbox environment wallet, choose one between this and Antom sandbox environment wallet
if (url.contains("www.sandbox.paypay") || url.contains("www.paypay.ne.jp") {
Intent schemeIntent = createSchemeIntent("paypay://");
if (schemeIntent != null && isAppIsInstalled(schemeIntent)) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW, parsedUri);
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
return true;
} else {
webView.loadUrl(url);
}
return true;
}
if (parsedUri != null && parsedUri.getHost().equals("psp.ac.alipay.com")) {
Bundle queryParameters = new Bundle();
// Go through all query parameters
for (String key : parsedUri.getQueryParameterNames()) {
// Add parameter name and value to the dictionary
queryParameters.putString(key, parsedUri.getQueryParameter(key));
}
if (queryParameters.getString("paypayRedirectUrl") != null) {
try {
// Concatenate PayPay parameters
String paypayRedirectUrl = queryParameters.getString("paypayRedirectUrl");
String decodedUriString = URLDecoder.decode(paypayRedirectUrl, "UTF-8");
String refreshUrl = decodedUriString + "&one_time_token=" + queryParameters.getString("one_time_token") + "&ppSmartPayment=1";
// Refresh or open the payment page, this payment page will not launch the paypay app
webView.loadUrl(refreshUrl);
} catch (Exception e) {
Log.d(TAG, "handleIntent: ", e);
}
}
}
return super.shouldOverrideUrlLoading(view, request);
}
}
/**
* Create scheme intent
* @param url scheme url
* @return Intent object
*/
private Intent createSchemeIntent(String url) {
Intent intent;
try {
intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
intent.addCategory("android.intent.category.BROWSABLE");
intent.setComponent(null);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
intent.setSelector(null);
}
} catch (URISyntaxException e) {
showToast(LoadWebViewActivity.this,
"The third-party app is not installed!
您所打开的第三方App未安装!");
}
return intent;
}
Please use the following code to check whether a third-party app is installed.
/**
* Check whether a third-party app is installed
*
* @param intent Intent object
* @return Whether the app is installed
*/
private boolean isAppIsInstalled(Intent intent) {
try {
List<ResolveInfo> resolves = getPackageManager().queryIntentActivities(intent, 0);
return !resolves.isEmpty();
} catch (Exception e) {
return false;
}
}
}
To comply with Android system privacy and security policies, you need to add a <queries>
tag in AndroidManifest.xml and configure the package name of the payment application within it. This ensures that payment redirection links can properly invoke the corresponding payment app.
<queries>
<package android:name="jp.ne.paypay.android.app" />
<package android:name="com.iap.linker_portal" />
</queries>
Common questions
Q: If authorization is successful but payment fails, how should subsequent payments be handled?
A: After authorization, if payment fails, the following three scenarios may occur. Please handle them accordingly:
- If authorization is successful but payment fails, the token remains valid in the browser. Therefore, during subsequent payments, only the PayPay payment confirmation page will be displayed, without redirecting to the PayPay app.
- If during the initial authorization, the authentication is completed only on the PayPay side and redirects back to the merchant side without redirecting again to PayPay's paypayRedirectUrl, it indicates authorization failure. The token will not take effect in the browser, and the buyer needs to be guided to re-authorize and complete the payment.
- If the buyer clears the browser cache, deletes app data, or reinstalls the app after successful initial authorization, the token will become invalid. The buyer must be guided to re-authorize and complete the payment.