Apple Pay

Apple Pay lets customers pay in one tap with cards stored in their Apple Wallet, authenticated with Face ID or Touch ID — no manual card entry. The SDK provides a native Apple Pay button that handles the payment sheet and result handling for you.

Order PageApple Payment sheet

Flow: user taps the Apple Pay button → Apple Pay sheet opens → user confirms with Face ID / Touch ID → result is returned via PBLPaymentResult.

Prerequisites

payabl. requirements

  • The SDK is added to your project — see iOS SDK.
  • Your backend can create a session via /mobile/init, and the request must include the country parameter for Apple Pay sessions — see Setup Your Server.

Apple Pay certificate exchange

To decrypt Apple Pay tokens, payabl. and your Apple Developer account must complete a certificate exchange. Repeat these steps separately for sandbox and production — you will need two CSR files and two Apple Merchant IDs in total.

  1. Request a CSR: contact [email protected] to generate a Certificate Signing Request (CSR) file.
  2. Create an Apple Merchant ID in your Apple Developer account under Identifiers → Merchant IDs.
  3. Sign the CSR: upload the CSR to your Apple Merchant ID. Apple issues a Payment Processing Certificate.
  4. Send both back: provide the Apple Merchant ID and the issued certificate to [email protected] so we can configure it in our system.
  5. Configure Xcode: enable the Apple Pay capability in Signing & Capabilities and select your Apple Merchant ID. Use the same ID to initialize the SDK (appleMerchantId in PBLConfiguration).

Device and account setup (for testing)

Integration

The SDK drives the payment flow through delegates. Your view model adopts:

  • PBLApplePayTapDelegate — provides the session configuration when the user taps the button, and receives the payment result.
  • PBLErrorDelegate — receives SDK errors raised outside the payment result.

1. Fetch session configuration

Request a session from your backend and build a PBLConfiguration. Create a new session for every payment attempt. The appleMerchantId must match the Merchant ID from the certificate exchange and your Xcode capability.

import SwiftUI
import PayablMerchant
import Combine
import PassKit

class DemoCartViewModel: ObservableObject {
    var pblApplePay: PBLApplePay?
    @Published var pblApplePayLoaded: Bool = false
    var configuration: PBLConfiguration?

    // In your server, this endpoint should call the /mobile/init API
    let backendCheckoutUrl = URL(string: "backend_endpoint/payment_page")!

    func prepareOrder() async -> PBLConfiguration? {
        var request = URLRequest(url: backendCheckoutUrl)
        request.httpMethod = "POST"

        await withCheckedContinuation { continuation in
            let task = URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
                guard let data = data,
                      let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any]
                else { return }

                let sessionId = json["sessionId"] as! String
                let ephemeralKey = json["empheralKey"] as! String
                let transactionId = json["transactionId"] as! Int

                self?.configuration = PBLConfiguration(
                    sessionId: sessionId,
                    ephemeralKey: ephemeralKey,
                    customerId: "", // not used for Apple Pay
                    environment: .sandbox, // use .production when going live
                    transactionId: transactionId,
                    appleMerchantId: "merchant.payabl.isdk" // your Apple Merchant ID
                )
                continuation.resume()
            }
            task.resume()
        }
        return configuration
    }
}

2. Adopt the delegates

extension DemoCartViewModel: PBLApplePayTapDelegate {
    // Called when the user taps the button — load the session, then hand the config back to the SDK
    func applePayTapped(onLoadSessionCompleted: @escaping (PBLConfiguration) -> Void) {
        Task {
            guard let config = await prepareOrder() else { return }
            onLoadSessionCompleted(config)
        }
    }

    // Called with the final result of the payment
    func applePayCompleted(result: PBLPaymentResult) {
        handlePaymentResult(result)
    }
}

extension DemoCartViewModel: PBLErrorDelegate {
    func errorOccured(error: any Error) {
        // Handle SDK errors (e.g., configuration or session issues)
        print("error from sdk: ", error)
    }
}

3. Add the button

Create the PBLApplePay component with your chosen button style and place its button in your view.

struct ContentView: View {
    let cartVM = DemoCartViewModel()

    var body: some View {
        VStack {
            if cartVM.pblApplePayLoaded {
                cartVM.pblApplePay?.button
                    .frame(maxWidth: .infinity)
            }
        }
        .padding()
        .onAppear {
            cartVM.pblApplePay = PBLApplePay(style: .whiteOutline, delegate: cartVM, errorDelegate: cartVM)
            cartVM.pblApplePayLoaded = true
        }
    }
}

Button styles — all natively supported Apple Pay button styles are available:

StyleAppearance
.whiteWhite button with black lettering
.whiteOutlineWhite button with black lettering and a black outline
.blackBlack button with white lettering
.automaticAdapts automatically to Light Mode / Dark Mode
📘

Follow Apple's Human Interface Guidelines for Apple Pay for button placement and sizing — Apple reviews this during App Review.

4. Handle the result

applePayCompleted returns a PBLPaymentResult. Handle all three cases.

func handlePaymentResult(result: PBLPaymentResult) {
    switch result {
    case .completed:
        // Payment successful — update order status
        break
    case .canceled:
        // User dismissed the Apple Pay sheet
        break
    case .failed:
        // Payment failed — inspect the result for the error code
        break
    }
}

Testing

Use the sandbox environment (.sandbox) with your sandbox Apple Merchant ID. Set up a sandbox tester Apple ID and add Apple's test cards to Wallet following Apple Pay sandbox testing.

For test data across all payment methods, see Testing.

Common issues

IssueCause & resolution
Apple Pay button doesn't appearApple Pay capability not enabled in Xcode, no Merchant ID selected, or no card available in Wallet on the device.
Sheet opens but payment failsCertificate exchange incomplete for this environment, appleMerchantId doesn't match the configured Merchant ID, or country missing from /mobile/init. See Setup Your Server.
Works in sandbox, fails in productionProduction certificate exchange not completed — sandbox and production require separate CSRs and Merchant IDs.
Payment fails after some months in productionPayment Processing Certificates expire — renew via a fresh certificate exchange before expiry.

When something goes wrong, see Error Handling & Troubleshooting.