Apple Pay

iOS SDK – Headless Apple Pay

Headless Apple Pay lets you present the Apple Pay sheet and complete a payment from your own UI, without using the SDK's built-in payment screens. You design the button and checkout flow; the SDK handles the Apple Pay sheet and the payment itself, then reports the result back to you.

When to use it

  • You want a fully custom checkout screen (your own Apple Pay button, layout and copy).
  • You only need Apple Pay and don't want to present the SDK's payment UI.

If you're happy with the SDK's standard payment UI, you don't need headless mode.

Before you start

Prerequisites

xCode VersioniOS VersionSwift Version
Download Geidea iOS SDK Version1.5.1
13 and above
  • A session ID. Every headless payment runs against a payment session, passed to the SDK as sessionId.
  • An Apple Pay merchant ID. Passed to the SDK through ApplePayConfigurations(merchantId:). Your app must be set up for Apple Pay with that merchant ID (Apple Pay capability enabled in Xcode and the merchant ID registered in your Apple Developer account).

Step 1: Build a headless configuration

Create a HeadlessGDPaymentSDKConfiguration for the session you want to pay.

func makeHeadlessConfiguration(sessionId: String) -> HeadlessGDPaymentSDKConfiguration {
    HeadlessGDPaymentSDKConfiguration(
        sessionId: sessionId,
        applePayConfig: ApplePayConfigurations(merchantId: applePayMerchantId),
        language: selectedLanguage,
        environmentType: selectedEnvironmentType,
        region: selectedRegion
    )
}
ParameterDescription
sessionIdThe ID of the payment session this payment belongs to.
applePayConfigApple Pay settings. Create it with ApplePayConfigurations(merchantId:) using your Apple Pay merchant ID.
languageThe language the SDK should use.
environmentTypeThe SDK environment to run against (for example test or production).
regionThe region your merchant account belongs to.

Step 2: Configure the SDK for headless mode

Pass the configuration to configureSDKForHeadless(configuration:) on the shared SDK instance. This call can throw, so call it with try inside a do/catch and don't start a payment if it fails.

do {
    try GDPaymentSDK.sharedInstance().configureSDKForHeadless(configuration: configuration)
} catch {
    // Configuration failed: show an error and don't call payWithApplePay.
    return
}

Step 3: Present Apple Pay with payWithApplePay

Call payWithApplePay(amount:countryCode:currencyCode:completion:) from your own button's action. The SDK opens the Apple Pay sheet and calls your completion handler when the flow ends. Call it from the main thread (for example from a @MainActor function), since it presents UI.

ParameterTypeDescription
amountDoubleThe amount to charge.
countryCodeStringTwo-letter country code, for example "EG".
currencyCodeStringCurrency code of the payment, for example "EGP".
completionclosureCalled once with the payment result.

Step 4: Handle the result

The completion handler receives one of three results:

ResultMeaningWhat to do
.successThe payment completed.Show your confirmation screen.
.failure(let error)The payment could not be completed.Show an error and let the user try again or choose another method.
.cancelledThe user dismissed the Apple Pay sheet.Return to checkout quietly; this is not an error.

Full example

A complete flow triggered from your own Apple Pay button:

@MainActor
func payWithApplePay(sessionId: String) {
    guard let amount = Double(totalAmount) else {
        showError("Invalid amount")
        return
    }

    let configuration = HeadlessGDPaymentSDKConfiguration(
        sessionId: sessionId,
        applePayConfig: ApplePayConfigurations(merchantId: applePayMerchantId),
        language: selectedLanguage,
        environmentType: selectedEnvironmentType,
        region: selectedRegion
    )

    do {
        try GDPaymentSDK.sharedInstance().configureSDKForHeadless(configuration: configuration)
    } catch {
        showError("Couldn't start Apple Pay: \(error.localizedDescription)")
        return
    }

    GDPaymentSDK.sharedInstance().payWithApplePay(
        amount: amount,
        countryCode: "EG",
        currencyCode: "EGP"
    ) { [weak self] result in
        guard let self else { return }
        switch result {
        case .success:
            self.showPaymentConfirmation()
        case .failure(let error):
            self.showError("Payment failed: \(error.localizedDescription)")
        case .cancelled:
            break // The user closed the Apple Pay sheet; stay on checkout.
        }
    }
}

showError and showPaymentConfirmation stand in for your own UI code.

Tips

  • Build the configuration and call configureSDKForHeadless before each payment, using the session ID for that payment.
  • Validate the amount before calling payWithApplePay rather than force-unwrapping it.
  • Treat .cancelled separately from .failure so users who simply close the sheet don't see an error.

Did this page help you?