Antom, leading provider of tailored payment solutions

Accept payments with PayPay Smart Payment

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.

User experience

The user experience for the first payment and subsequent payments is as follows:
First payment
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.
Web
App
Subsequent payments
For subsequent payments, the PayPay wallet app will not be launched, and the payment will be completed directly on the merchant's side.
Web
App

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:
​
When placing an order
normalUrl redirection
Merchant page redirection
Asynchronous Notification
First payment
No difference. Call the
pay (One-time Payments) API to obtain the normalUrl.
No difference.
The buyer is redirected via a WebView with source=embedded appended to the normalUrl.
Launch the authorization page of the PayPay app.
Obtain the paypayRedirectUrl and one_time_token parameters from the paymentRedirectUrl and redirect to this URL again.
No difference. Only payment success and payment failure notifications are provided, with no authorization result notifications.
Subsequent payments
Display the PayPay payment page on an H5 page.
No additional parameters appended to paymentRedirectUrl, and no further redirection is required.

Payment flow

The following are flow chart for the first payment and subsequent payment:
First payment
Subsequent payments

Integration preparations

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:
image.png
Edge
Lastest 2 versions
image.png
Firefox
Lastest 2 versions
image.png
Chrome
Version 87 and above
image.png
Safari
Version 15 and above
  • 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.

Integration steps

Start your integration by taking the following steps:
  1. Create a payment order
  2. Get the payment continuation URL
  3. 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://.
The following shows a sample of how to call the pay (One-time Payments) API:
{
  "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:
Web/WAP
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.
iOS
Process the payment continuation URL (normalUrl) returned by Antom according to the following steps:

1. Append the parameters

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=&region=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&region=SG&source=embedded&isAuthorized=true&one_time_token=4f4c7877-553b-438c-9739-d64109a2bd66&ppSmartPayment=1

4. After payment

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.
Android
Process the payment continuation URL (normalUrl) returned by Antom according to the following steps:

1. Append the parameters

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=&region=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'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:
/**
 * 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&region=SG&source=embedded&isAuthorized=true&one_time_token=4f4c7877-553b-438c-9739-d64109a2bd66&ppSmartPayment=1

4. After payment

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:
Common scenarios
Asynchronous notification status
First payment: Authorization successful and payment successful
No notification for successful authorization. A notification will be sent after the authorized payment is successful.
First payment: Authorization successful but payment failed
No notification for successful authorization. A notification will be sent if the authorized payment fails.
First payment: Authorization failed
A payment failure notification is sent after the order is closed.

Subsequent payments
Payment notifications are sent based on the payment status.
Antom provides the capability to send asynchronous notifications and also supports actively querying payment results by calling the inquiryPayment API.
Payment success
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"
  }
}
Payment failure
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"
  }
}

Best practices

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.
iOS
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>
Android
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.