SDK-Apple Pay
Note:
Application Required
To use this feature, please contact your BD/AM or technical support team in advance to request activation.
The Client SDK mode is designed for native iOS applications. With the PayerMax Apple Pay SDK, you can provide a native Touch ID / Face ID payment experience in your iOS App, while eliminating the need to handle the complex decryption of the Apple Pay Token yourself. The PayerMax backend decrypts the token and completes the acquiring process on your behalf, requiring only minimal Swift code to implement a complete payment flow.
Before you begin, you must have joined the Apple Developer Program.
1. Interaction Flow
The sequence diagram below illustrates the interactions among the Merchant App, Merchant Server, PayerMax SDK, Apple PassKit, and PayerMax Backend.
%%{init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#e6f0ff',
'primaryTextColor': '#333',
'primaryBorderColor': '#5b9bd5',
'lineColor': '#888',
'actorMargin': 40,
'noteBkgColor': '#0056b3',
'noteTextColor': '#ffffff',
'noteBorderColor': '#004a99'
}
}}%%
sequenceDiagram
participant App as Merchant App
participant MerchantServer as Merchant Server
participant PMSDK as PayerMax SDK
participant PassKit
participant PMBackend as PayerMax Backend
%% Process Steps
App->>MerchantServer: Request to create order
MerchantServer->>PMBackend: Call /applyApplePaySession (Amount/Currency/Country)
PMBackend-->>MerchantServer: amount / currency / country / merchantId / networks / orderToken
MerchantServer-->>App: Return order parameters (amount/currency/country/merchantId/networks/orderToken)
App->>PMSDK: present(PKPaymentRequest)
PMSDK->>PassKit: Pop up Apple Pay sheet
PassKit-->>PMSDK: didAuthorize(Encrypted PKPayment token)
PMSDK->>PMBackend: POST /orderAndPay (with orderToken and encrypted payload)
PMBackend-->>PMSDK: Acquiring result (Success/Failure)
PMSDK-->>App: completion(result)
2. Pre‑integration Steps
Before writing any code, you must complete Apple’s asset configuration and exchange the necessary certificates with PayerMax. The following steps are prerequisites for enabling Apple Pay.
2.1 Create Merchant IDs
Log in to the Apple Developer website and register a new Merchant ID in the Certificates, Identifiers & Profiles -> Identifiers -> Merchant IDs page. This ID uniquely identifies your merchant identity and plays a key role in the Apple Pay encryption flow.
Fill in the description and identifier in the form. The description is for your own reference and can be changed later. PayerMax recommends using your application’s name as the identifier (for example, merchant.com.{{YOUR_APP_NAME}}).
2.2 Configure Payment Processing Certificate
Create a certificate for your app to encrypt payment data. PayerMax adopts a backend‑held decryption approach, meaning that the PayerMax backend holds the private key and is responsible for decrypting the Apple Pay Token – your client never touches any private key.
Configuration steps:
- Contact PayerMax technical support to obtain a dedicated Certificate Signing Request (CSR) file.
- In the Apple Developer portal, use the CSR file provided by PayerMax to generate a Payment Processing Certificate for your Merchant ID.
- Submit the generated certificate file (
.cer) to PayerMax, and PayerMax will import and configure it on the backend.
Note:
You must use the CSR file provided by PayerMax to generate the certificate – do not generate your own CSR. A single CSR can only be used to issue one certificate. If you change your Apple Merchant ID, you must contact PayerMax technical support again to obtain a new CSR and certificate.
3. API Introduction
3.1 API List
| Step | Call Direction | Type | API PATH |
|---|---|---|---|
| 4.3 Create Payment Request | Merchant Server -> PayerMax | Backend API | /applyApplePaySession |
| 4.4 Show Payment Form and Submit Payment | SDK -> PayerMax | Backend API | /orderAndPay |
| 4.5 Get Payment Result | PayerMax -> Merchant | Backend API | /collectResultNotifyUrl |
3.2 Environment Information
Test Environment:
https://pay-gate-uat.payermax.com/aggregate-pay/api/gateway/<API_PATH>Production Environment:
https://pay-gate.payermax.com/aggregate-pay/api/gateway/<API_PATH>
3.3 Request Headers
{
"Accept": "application/json",
"sign": "Please refer to the signing rules: https://docs-v2.payermax.com/202606-version/developer/config-settings.html",
"Content-Type": "application/json"
}4. Start Integration
4.1 Get the SDK
PayerMax recommends using modern dependency management tools to import the Apple Pay SDK, supporting both Swift Package Manager (SPM) and CocoaPods.
1. Swift Package Manager (SPM)
In Xcode, select File > Add Package Dependencies..., enter the following repository URL, choose the latest version, and add the PayerMaxApplePay module to your application target.
https://github.com/payermax/payermax-ios-sdk2. CocoaPods
Add the following dependency to your Podfile and run pod install:
pod 'PayerMax/ApplePay'4.2 Integrate Xcode and Configure Capabilities
Open your project settings in Xcode, select the Target, then navigate to the Signing & Capabilities tab. Click the + Capability button in the top-left corner, search for and add the Apple Pay capability from the pop-up list.
In the Apple Pay configuration section, check the Merchant ID created in Section 2.1. This action will write the Merchant ID into the app’s entitlement file, granting your application the permission to launch the Apple Pay payment sheet.
4.3 Initialization Configuration and Availability Check
Initialize the SDK with the Publishable Key obtained from the PayerMax Merchant Backend upon app launch (e.g., inside AppDelegate). Before displaying the Apple Pay button to end users, call PMApplePayConfiguration.canMakePayments() to verify whether the current device supports Apple Pay and the user has bound valid payment cards.
import UIKit
import PayerMaxApplePay
import PassKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Initialize SDK with the Publishable Key obtained from PayerMax Merchant Backend
PMAPIClient.defaultPublishableKey = "your_publishable_key"
return true
}
}
class CheckoutViewController: UIViewController {
let applePayButton = PKPaymentButton(paymentButtonType: .buy, paymentButtonStyle: .black)
override func viewDidLoad() {
super.viewDidLoad()
// Show button only if the device supports Apple Pay and the user has bound payment cards
if PMApplePayConfiguration.canMakePayments() {
applePayButton.addTarget(self, action: #selector(handleApplePayButtonTapped), for: .touchUpInside)
view.addSubview(applePayButton)
}
}
}4.4 Initiate Payment Request & Result Handling
When the user taps the Apple Pay button, the merchant App first requests its own server to create an order. The merchant server calls PayerMax’s /applyApplePaySession API to obtain payment parameters including amount, currency, merchantId, networks as well as the orderToken, then returns these data to the App.
After receiving the parameters, the App calls PMApplePayConfiguration.paymentRequest to construct a PKPaymentRequest object, and invokes PMApplePayContext to present the native Apple Pay payment sheet. Once the user authorizes the payment via Face ID or Touch ID, the SDK automatically submits the encrypted token together with the orderToken to PayerMax backend’s /orderAndPay API for acquiring confirmation. The final payment result will be passed back to the merchant App through delegate callback.
Server Side
The merchant server needs to expose an API endpoint, which internally calls PayerMax /applyApplePaySession and returns the order parameters to the client.
// POST /applyApplePaySession Request Example
{
"version": "1.5",
"keyVersion": "1",
"requestTime": "2025-05-14T16:30:27.174+08:00",
"appId": "your_app_id",
"merchantNo": "your_merchant_no",
"data": {
"outTradeNo": "your_order_id",
"totalAmount": 50.00,
"currency": "USD",
"country": "US",
"userId": "your_user_id",
"subject": "Your Order Subject"
}
}// Response Example
{
"code": "APPLY_SUCCESS",
"msg": "Success.",
"data": {
"amount": "50.00",
"currency": "USD",
"country": "US",
"merchantId": "merchant.com.yourcompany.yourapp",
"networks": ["visa", "masterCard", "amex"],
"orderToken": "T2025051210335071234567"
}
}客户端
@objc func handleApplePayButtonTapped() {
// Fetch order parameters from your server
// Your server is responsible for calling PayerMax /applyApplePaySession API and returning results to App
fetchOrderParamsFromYourServer { [weak self] result in
guard let self = self else { return }
switch result {
case .success(let orderParams):
// orderParams contains amount, currency, country, merchantId, networks, orderToken returned by server
let paymentRequest = PMApplePayConfiguration.paymentRequest(
withMerchantIdentifier: orderParams.merchantId, // From server
country: orderParams.country, // From server
currency: orderParams.currency // From server
)
// Configure summary items for payment request
// The last line must represent your company; it will be prefixed with the word "Pay" (e.g. "Pay Your Company $50")
// Amount comes from server and must not be determined by client side
paymentRequest.paymentSummaryItems = [
PKPaymentSummaryItem(
label: "Your Company Name",
amount: NSDecimalNumber(string: orderParams.amount) // From server
)
]
// Store orderToken for subsequent /orderAndPay request
self.orderToken = orderParams.orderToken
// Initialize PMApplePayContext and present Apple Pay sheet
// Note: present must be triggered directly by user gesture, cannot be called delayed after async operations
if let applePayContext = PMApplePayContext(
paymentRequest: paymentRequest,
delegate: self
) {
applePayContext.presentApplePay(on: self)
} else {
print("Failed to initialize Apple Pay, please check Merchant ID configuration")
}
case .failure(let error):
print("Failed to fetch order parameters: \(error.localizedDescription)")
}
}
}
// MARK: - PMApplePayContextDelegate
extension CheckoutViewController: PMApplePayContextDelegate {
// SDK calls back this method after user authorization, you need to return server-side orderToken for subsequent /orderAndPay
func applePayContext(
_ context: PMApplePayContext,
didCreatePaymentMethod paymentMethod: PMPaymentMethod,
paymentInformation: PKPayment
) async throws -> String {
// Return the orderToken issued by server when creating order
// SDK will automatically call PayerMax /orderAndPay with this token and encrypted payload
return self.orderToken
}
// SDK triggers this callback after payment processing, status indicates final payment result
func applePayContext(
_ context: PMApplePayContext,
didCompleteWith status: PMApplePayContext.PaymentStatus,
error: Error?
) {
switch status {
case .success:
// Payment succeeded, display order confirmation page
print("Payment succeeded")
case .error:
// Payment failed, display error prompt
print("Payment failed: \(error?.localizedDescription ?? "")")
case .userCancellation:
// User actively cancelled the payment
break
@unknown default:
break
}
}
}Note: The amount must always be determined by the server side; the client is only responsible for display. Do not hardcode amounts on the client to prevent malicious tampering. The
/orderAndPayAPI is automatically invoked by the SDK after user authorization, no manual handling is required by merchants.
4.5 Obtain Payment Result
The .success status in the didCompleteWith callback of PMApplePayContextDelegate indicates that PayerMax backend has finished acquiring confirmation. In addition, PayerMax will push the final payment result to your server via asynchronous Webhook notifications.
It is recommended to listen to Webhook notifications instead of relying solely on client-side callbacks, so that payment status can be reliably obtained under exceptional scenarios such as the user closing the App. For details, please refer to Payment Result - Payment Result Notification.
5. Testing & Go-Live
5.1 Sandbox Testing
Apple Pay testing requires a dedicated sandbox environment. Regular test cards cannot be added to Apple Wallet on physical devices. Please follow the steps below for configuration:
- Create a Sandbox Tester account on the Apple Developer Website.
- On your test iPhone or iPad, navigate to Settings > App Store and sign in with the sandbox tester account.
- Go to Settings > Wallet & Apple Pay, then add a test card using the test card numbers provided by Apple.
- Use the sandbox environment Publishable Key during SDK initialization:
// Test Environment Initialization
PMAPIClient.defaultPublishableKey = "your_test_publishable_key"Note: In the sandbox environment, Apple Pay cannot be launched with
127.0.0.1, LAN IP orlocalhost. You must use an HTTPS domain name with a valid SSL certificate.
5.2 Switch to Production Environment
After testing is completed, replace the Publishable Key with the production environment value to finish the go-live switch.
// Production Environment Initialization
PMAPIClient.defaultPublishableKey = "your_live_publishable_key"6. Troubleshooting for Common Issues
If you encounter problems during integration, please first refer to the common causes and solutions listed in the table below.
| Fault Phenomenon | Possible Cause | Solution |
|---|---|---|
| Apple Pay sheet fails to pop up | Mismatched Merchant ID configuration | Check whether the Merchant ID checked in Apple Pay Capability within Xcode is completely consistent with the merchantId returned by the server-side /applyApplePaySession API. |
| Apple Pay sheet fails to pop up | No payment card bound on device or Apple Pay unsupported | Verify that PMApplePayConfiguration.canMakePayments() returns true.If it returns false, check whether a sandbox test card has been added to Wallet on the test device. |
| Backend fails to decrypt the returned token | Certificate generated with incorrect CSR file | Make sure the CSR file used in Apple Developer Console is provided by PayerMax instead of self-generated CSR. Contact PayerMax technical support to retrieve a new CSR if needed. |
| Apple Pay configuration invalid in Xcode | Xcode cached outdated certificate information | Toggle the Apple Pay Capability in Xcode (uncheck Merchant ID, save settings, then re-check it) to force a refresh of the entitlement configuration file. |
| Incorrect displayed payment amount | Inconsistent amount between client and server | Ensure the amount in paymentSummaryItems is strictly identical to the order amount returned by the server-side /applyApplePaySession API; otherwise it may trigger payment failure or risk control interception. |
| Duplicate deduction caused by network retries | Improper idempotency handling | The SDK passes Apple’s returned transactionIdentifier to PayerMax backend as the Idempotency-Key internally. Confirm your server correctly processes this idempotent key to avoid duplicate charges. |
