Skip to content
Developer Tools
Accelerate development using AI assistants and tools

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:

  1. Contact PayerMax technical support to obtain a dedicated Certificate Signing Request (CSR) file.
  2. In the Apple Developer portal, use the CSR file provided by PayerMax to generate a Payment Processing Certificate for your Merchant ID.
  3. 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

StepCall DirectionTypeAPI PATH
4.3 Create Payment RequestMerchant Server -> PayerMaxBackend API/applyApplePaySession
4.4 Show Payment Form and Submit PaymentSDK -> PayerMaxBackend API/orderAndPay
4.5 Get Payment ResultPayerMax -> MerchantBackend 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

json
{
  "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.

plain
https://github.com/payermax/payermax-ios-sdk

2. CocoaPods

Add the following dependency to your Podfile and run pod install:

ruby
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.

swift
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.

json
// 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"
  }
}
json
// 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"
  }
}

客户端

swift
@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 /orderAndPay API 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:

  1. Create a Sandbox Tester account on the Apple Developer Website.
  2. On your test iPhone or iPad, navigate to Settings > App Store and sign in with the sandbox tester account.
  3. Go to Settings > Wallet & Apple Pay, then add a test card using the test card numbers provided by Apple.
  4. Use the sandbox environment Publishable Key during SDK initialization:
swift
// 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 or localhost. 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.

swift
// 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 PhenomenonPossible CauseSolution
Apple Pay sheet fails to pop upMismatched Merchant ID configurationCheck 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 upNo payment card bound on device or Apple Pay unsupportedVerify 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 tokenCertificate generated with incorrect CSR fileMake 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 XcodeXcode cached outdated certificate informationToggle 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 amountInconsistent amount between client and serverEnsure 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 retriesImproper idempotency handlingThe 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.

Was this page helpful?

Thank you for your help in improving PayerMax Product Docs!

Released under the MIT License.