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 Version | iOS Version | Swift Version |
|---|---|---|
| Download Geidea iOS SDK Version | 1.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
)
}| Parameter | Description |
|---|---|
sessionId | The ID of the payment session this payment belongs to. |
applePayConfig | Apple Pay settings. Create it with ApplePayConfigurations(merchantId:) using your Apple Pay merchant ID. |
language | The language the SDK should use. |
environmentType | The SDK environment to run against (for example test or production). |
region | The 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.
| Parameter | Type | Description |
|---|---|---|
amount | Double | The amount to charge. |
countryCode | String | Two-letter country code, for example "EG". |
currencyCode | String | Currency code of the payment, for example "EGP". |
| completion | closure | Called once with the payment result. |
Step 4: Handle the result
The completion handler receives one of three results:
| Result | Meaning | What to do |
|---|---|---|
.success | The 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. |
.cancelled | The 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
configureSDKForHeadlessbefore each payment, using the session ID for that payment. - Validate the amount before calling
payWithApplePayrather than force-unwrapping it. - Treat
.cancelledseparately from.failureso users who simply close the sheet don't see an error.
Updated about 3 hours ago